赞
踩
本篇文章从硬件层面到软件层面详细介绍了如何实现OpenMV与STM32/msp432p401r串口通信,并介绍了一下串口通讯协议的原理,文末附上完整的源代码。
由图知RX—P5 ---TX—P4
本文以RX_PA3 --TX_PA2为例
本文以RX_P3^2--TX_P3^3 为例
注意:连接引脚时一定要注意主控的TX连接OpenMV的RX,主控的RX连接OpenMV的TX
运行条件:主控先通过串口给OpenMV发送char类型数据'0'作为运行模式。针对电赛需求,OpenMV只需要收到模式数据即可,可以不加帧头与帧尾,而直接判断获取的内容,详细代码如下。
- # 作者 记得开心①点
- # 创作日期 2023.8.7
-
- import sensor, image, time ,math,pyb
- from pyb import UART
- uart = UART(3,115200)#设置串口波特率
-
- #摄像头初始化
- sensor.reset()#复位和初始化传感器。
- sensor.set_pixformat(sensor.RGB565)#设置像素格式为RGB565(或GRAYSCAL)
- sensor.set_framesize(sensor.VGA)#设置帧大小为VGA (480x640)
- sensor.skip_frames(time = 2000)#等待设置生效
- sensor.set_auto_gain(False)#关闭自动增益
- sensor.set_auto_whitebal(False) #关闭白平衡
- clock = time.clock()#创建一个时钟对象来跟踪FPS
-
- #初始化三个板载灯
- red_led = pyb.LED(1)
- green_led = pyb.LED(2)
- blue_led = pyb.LED(3)
- red_led.on();#OpenMV初始化成功长亮红灯
-
- #红色阈值
- red_threshold = (0, 100, 12, 73, -123, 127)
-
- #初始化所需标志位
- i=0
- pattern=-1#模式
-
- #寻找最大色块
- def find_max(blobs):
- max_blob = None
- max_size = 0
- for blob in blobs:
- if blob[2]*blob[3]>max_size:
- max_blob=blob
- max_size=blob[2]*blob[3]
- return max_blob
-
- #获取数据
- def data_get():
- global i
- global pattern
- getrx = uart.readchar()#获取char类型数据
- if getrx == 0 or getrx==1 or getrx==2 or getrx==3:
- pattern = getrx
- else:
- i=i+1
- if i>=20:#如果收到的数据不正确20次以上,OpenMV闪蓝灯
- for i in range(1,10):
- for j in range(1,30):
- blue_led.on()
- for j in range(1,30):
- blue_led.off()
-
- #主循环
- while(True):
- clock.tick()
- if uart.any():#串口有任何值发送过来
- data_get()#获取运行模式
- if pattern==0:
- img = sensor.snapshot().lens_corr(1.6)#鱼眼矫正
- blobs = img.find_blobs([red_threshold],roi=[80,80,320,320])
- if blobs:
- red_led.off()
- green_led.on()#找到色块亮绿灯
- blue_led.off()
- max_blob = find_max(blobs)#返回最大的色块
- img.draw_rectangle(max_blob.rect())#画出找到色块
- #发送数据
- data=bytearray([0xa3,0xb3,int(max_blob.cx()/2),int(max_blob.cy()/2),0xc3])
- uart.write(data)
- else:#未找到色块返回0,0n
- red_led.off()
- green_led.on()#未找到色块亮青蓝色灯
- blue_led.on()
- #发送数据
- data=bytearray([0xa3,0xb3,int(0),int(0),0xc3])
- uart.write(data)
- else:#摄像头未执行任何模式返回255,255
- red_led.on()
- green_led.on()#未执行任何模式亮黄灯
- blue_led.off()
- #发送数据
- data=bytearray([0xa3,0xb3,int(255),int(255),0xc3])
- uart.write(data)
/*****openmv.h*****/(32部分源文件以连接的硬件命名)
- //作者 记得开心①点
- //日期 2023.8.7
-
- #ifndef __OPENMV_H
- #define __OPENMV_H
-
- #include <stdio.h>
-
- extern int openmv_data[4];//已经声明全局变量,在任意文件直接调用即可
- void openmv_Init(void);
- void openmv_SendByte(uint8_t Byte);
-
-
- #endif
-
-
/*****openmv.c*****/(32部分源文件以连接的硬件命名)
- //作者 记得开心①点
- //日期 2023.8.7
-
- #include "stm32f10x.h" // Device header
-
- void openmv_Init(void)
- {
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
-
- GPIO_InitTypeDef GPIO_InitStructure;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//推挽输出模式
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_Init(GPIOA, &GPIO_InitStructure);
-
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//ÉÏÀÊäÈë»ò¸¡¿ÕÊäÈë
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_Init(GPIOA, &GPIO_InitStructure);
-
- USART_InitTypeDef USART_InitStructure;
- USART_InitStructure.USART_BaudRate = 115200;//²¨ÌØÂÊ
- USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件流控制
- USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;//串口模式配置
- USART_InitStructure.USART_Parity = USART_Parity_No;//无校验位
- USART_InitStructure.USART_StopBits = USART_StopBits_1;//一位停止位
- USART_InitStructure.USART_WordLength = USART_WordLength_8b;//八位(不需要校验)
- USART_Init(USART2, &USART_InitStructure);
-
- USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
-
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
-
- NVIC_InitTypeDef NVIC_InitStructure;
- NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
- NVIC_Init(&NVIC_InitStructure);
-
- USART_Cmd(USART2, ENABLE);
- }
-
- void openmv_SendByte(uint8_t Byte)
- {
- USART_SendData(USART2, Byte);
- while (USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET);//等待发送完成
- }
-
- int openmv_flag=0;
- int openmv_i=0;
- int openmv_data[4]={0};
- int openmv_rx=0;
-
- void USART2_IRQHandler(void)
- {
- if (USART_GetITStatus(USART2, USART_IT_RXNE) == SET)//判断接受中断标志位
- {
- openmv_rx=USART_ReceiveData(USART2);//获取数据
- if(openmv_flag==0&&openmv_rx==0xa3)//判断第一个帧头
- {
- openmv_flag=1;
- }
- else if(openmv_flag==1&&openmv_rx==0xb3)判断第二个帧头
- {
- openmv_flag=2;
- }
- else if(openmv_flag==3)
- {
- openmv_flag=3;
- openmv_data[openmv_i++]=openmv_rx;//获取数据
- }
- else if(openmv_flag==3)
- {
- openmv_flag=4;
- openmv_data[openmv_i++]=openmv_rx;//获取数据
- }
- else if(openmv_flag==4&&openmv_rx==0xc3)//判断最后一个帧头
- {
- openmv_flag=0;
- openmv_i=0;
- }
- USART_ClearITPendingBit(USART2, USART_IT_RXNE);//清除接收中断标志位
- }
- }
-
-
-
-
/*****openmv4.h*****/(msp432部分源文件以连接的硬件命名)
这里baudrate_calculate文件附在其后,这个文件创建后在openmv4.h中包含即可,感谢某站up,m-RNA的msp432p401r开源视频教程。
- //作者 记得开心①点
- //日期 2023.8.7
-
- #ifndef _openmv4_H
- #define _openmv4_H
-
- #include "sysinit.h"
- #include "baudrate_calculate.h"
-
- extern int openmv_data[8];//已经声明全局变量,在任意文件内直接调用即可
- void openmv_sentdata(char mode);
- void openmv4_uart_init(void);
-
- #endif
-
/*****openmv4.c*****/(msp432部分源文件以连接的硬件命名)
- //作者 记得开心①点
- //日期 2023.8.7
- #include "openmv4.h"
-
- //初始化IO 串口2
- // bound:波特率
- void openmv4_uart_init(uint32_t baudRate)
- {
- //固件库v3_40_01_02
- //默认SMCLK 48MHz 比特率
- const eUSCI_UART_ConfigV1 uartConfig =
- {
- EUSCI_A_UART_CLOCKSOURCE_SMCLK, //48mhz时钟打开
- 312, // BRDIV = 312
- 8, // UCxBRF = 8
- 0, // UCxBRS = 1
- EUSCI_A_UART_NO_PARITY, // 无校验位
- EUSCI_A_UART_LSB_FIRST, // MSB First
- EUSCI_A_UART_ONE_STOP_BIT, //一位停止位
- EUSCI_A_UART_MODE, // 串口模式配置
- EUSCI_A_UART_OVERSAMPLING_BAUDRATE_GENERATION, // Oversampling
- EUSCI_A_UART_8_BIT_LEN // 字长八位(无需校验位)
- };
- eusci_calcBaudDividers((eUSCI_UART_ConfigV1 *)&uartConfig, baudRate); //配置波特率
-
- // 1.配置GPIO复用
- MAP_GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P3, GPIO_PIN2 | GPIO_PIN3, GPIO_PRIMARY_MODULE_FUNCTION);
- MAP_UART_initModule(EUSCI_A2_BASE, &uartConfig); // 3.初始化串口
- MAP_UART_enableModule(EUSCI_A2_BASE); // 4.开启串口模块
- MAP_UART_enableInterrupt(EUSCI_A2_BASE, EUSCI_A_UART_RECEIVE_INTERRUPT); // 5.开启接收中断
- //MAP_UART_enableInterrupt(EUSCI_A2_BASE, EUSCI_A_UART_TRANSMIT_INTERRUPT);//6.开启发送中断
- MAP_Interrupt_enableInterrupt(INT_EUSCIA2); // 7.开启串口端口中断
- }
-
- void openmv_sentdata(char mode)
- {
- //MAP_UART_transmitData(EUSCI_A2_BASE,0xa3);
- MAP_UART_transmitData(EUSCI_A2_BASE,mode);
- }
-
- int openmv_flag=0;
- int rx_data=0;
- int openmv_data[8]={0};
- int openmv_i=0;
-
- // Uart2接收中断
- void EUSCIA2_IRQHandler(void)
- {
- uint32_t status = MAP_UART_getEnabledInterruptStatus(EUSCI_A2_BASE);
- if (status & EUSCI_A_UART_RECEIVE_INTERRUPT_FLAG) //判断接受中断标志位
- {
-
- rx_data=MAP_UART_receiveData(EUSCI_A2_BASE);
- if(rx_data==0xA3&&openmv_flag==0)//判断头帧
- {
- openmv_flag=1;
-
- }
- else if(openmv_flag==1&&rx_data==0xb3)//判断第二帧
- {
- openmv_flag=2;
- }
- else if(openmv_flag==2)
- {
- openmv_flag=3;
- openmv_data[openmv_i++]=rx_data;//获取回传
- }
- else if(openmv_flag==3)
- {
- openmv_flag=4;
- openmv_data[openmv_i++]=rx_data;//获取回传
- }
- else if(openmv_flag==4&&rx_data==0xc3)//判断第三帧
- {
- openmv_flag=0;
- openmv_i=0;
- }
- MAP_UART_clearInterruptFlag(EUSCI_A2_BASE, EUSCI_A_UART_RECEIVE_INTERRUPT_FLAG); // 清除接收中断标志位
- }
- }
-
- void eusci_calcBaudDividers(eUSCI_UART_ConfigV1 *uart_config, uint32_t baudRate) //固件库v3_40_01_02
-
-
- {
- float maxAbsErrorInByte;
- float minAbsError;
- float error;
- uint8_t ii;
- uint16_t jj;
- uint16_t NN;
- uint32_t count;
- uint32_t clockRate;
-
- if (!uart_config || !baudRate) //传参错误 退出函数
- {
- //uart_warning_led(); //闪烁错误指示灯10次
- return;
- }
-
- if (uart_config->selectClockSource == EUSCI_A_UART_CLOCKSOURCE_SMCLK)
- clockRate = MAP_CS_getSMCLK();
- else if (uart_config->selectClockSource == EUSCI_A_UART_CLOCKSOURCE_ACLK)
- clockRate = MAP_CS_getACLK();
- else
- {
- uart_config->selectClockSource = EUSCI_A_UART_CLOCKSOURCE_SMCLK;
- clockRate = MAP_CS_getSMCLK();
- }
- if (baudRate > clockRate) //判断波特率是否大于时钟频率 是则退出函数
- {
- //uart_warning_led(); //闪烁错误指示灯10次
- return;
- }
- //var result = {UCOS16 : 0, UCBRx : 0, UCFx : 0, UCSx : 0, maxAbsError : 0};
-
- NN = (uint16_t)((float)clockRate / (float)baudRate); //应该是不需要floor
-
- minAbsError = 100000;
- for (jj = 0; jj <= 255; jj++)
- {
-
- maxAbsErrorInByte = 0;
- count = 0;
- for (ii = 0; ii <= 10; ii++)
- {
- count += NN + bitPosition(jj, 7 - (ii % 8));
-
- //error = (ii + 1) * baudPeriod - count * clockPeriod;
- error = (ii + 1) / (float)baudRate - count / (float)clockRate; //为了减少变量,改为此代码
-
- if (error < 0)
- error = -error;
-
- if (error > maxAbsErrorInByte)
- maxAbsErrorInByte = error;
- }
- if (maxAbsErrorInByte - minAbsError < -7.3e-12f) //这里就是“已知问题”
- {
- minAbsError = maxAbsErrorInByte;
- uart_config->secondModReg = jj;
- }
- }
-
- if (NN < 20)
- {
- uart_config->overSampling = 0;
- uart_config->clockPrescalar = NN;
- uart_config->firstModReg = 0;
- }
- else
- {
- uart_config->overSampling = 1;
- uart_config->clockPrescalar = (uint16_t)((float)NN / 16.0f); //应该是不需要floor
- uart_config->firstModReg = NN - (uart_config->clockPrescalar * 16);
- }
- //return minAbsError * baudRate * 100;
- }
/*****baudrate_calculate.h*****/
- /****************************************************/
- // MSP432P401R
- // 串口波特率计算
- // Bilibili:m-RNA
- // E-mail:m-RNA@qq.com
- /****************************************************/
-
- /****************************** 说明 ******************************
- *
- * 源码为TI官方编写,本人只是将JS程序移植到了C语言平台,仅作为学习使用。源码出处为:
- * http://software-dl.ti.com/msp430/msp430_public_sw/mcu/msp430/MSP430BaudRateConverter/index.html
- *
- * ? 已知问题:
- * 调试时发现某些情况下,C语言的小数的大小与JS的相差较大,
- * 导致了算出的UCSx(即secondModReg)不一样,
- * 这时如果出现不能准确传输时,请换一个波特率。
- *
- * ? 需要注意:
- * 波特率不能大于时钟频率,否则会退出函数
- *
- * ***************************** 版本说明 ******************************
- *
- * ? v1.2 2021/8/29
- * 注释掉了闪烁灯的代码
- *
- * ? v1.1 2021/8/27
- * 添加支持固件库v3_21_00_05
- *
- * ? v1.0 2021/8/25
- * 仅支持固件库v3_40_01_02
- *
- * ******************************* 结束 *******************************/
-
- #ifndef __RNA_BAUDRATE_CALCULATE_H
- #define __RNA_BAUDRATE_CALCULATE_H
- #include <ti/devices/msp432p4xx/driverlib/driverlib.h>
-
- //错误指示灯宏定义 方便移植使用
- //MSP432P401R 有两个红灯P1.0 P2.0
- //#define WARN_LED_1_PORT GPIO_PORT_P1
- //#define WARN_LED_2_PORT GPIO_PORT_P2
- //#define WARN_LED_1_PIN GPIO_PIN0
- //#define WARN_LED_2_PIN GPIO_PIN0
- //#define WARN_LED_INIT MAP_GPIO_setAsOutputPin
- //#define WARN_LED_ON MAP_GPIO_setOutputHighOnPin
- //#define WARN_LED_OFF MAP_GPIO_setOutputLowOnPin
-
- #ifdef EUSCI_A_UART_7_BIT_LEN
- void eusci_calcBaudDividers(eUSCI_UART_ConfigV1 *uart_config, uint32_t baudRate); //固件库v3_40_01_02
- #else
- void eusci_calcBaudDividers(eUSCI_UART_Config *uart_config, uint32_t baudRate); //固件库v3_21_00_05
- #endif
-
- #endif
/*****baudrate_calculate.c*****/
- /****************************************************/
- // MSP432P401R
- // 串口波特率计算
- // Bilibili:m-RNA
- // E-mail:m-RNA@qq.com
- /****************************************************/
-
- /****************************** 说明 ******************************
- *
- * 源码为TI官方编写,本人只是将JS程序移植到了C语言平台,仅作为学习使用。源码出处为:
- * http://software-dl.ti.com/msp430/msp430_public_sw/mcu/msp430/MSP430BaudRateConverter/index.html
- *
- * ? 已知问题:
- * 调试时发现某些情况下,C语言的小数的大小与JS的相差较大,
- * 导致了算出的UCSx(即secondModReg)不一样,
- * 这时如果出现不能准确传输时,请换一个波特率。
- *
- * ? 需要注意:
- * 波特率不能大于时钟频率,否则会退出函数
- *
- * ***************************** 版本说明 ******************************
- *
- * ? v1.2 2021/8/29
- * 注释掉了闪烁灯的代码
- *
- * ? v1.1 2021/8/27
- * 添加支持固件库v3_21_00_05
- *
- * ? v1.0 2021/8/25
- * 仅支持固件库v3_40_01_02
- *
- * ******************************* 结束 *******************************/
-
- #include "baudrate_calculate.h"
-
- //void uart_warning_led(void);
-
- /*
- * ======== bitPosition ========
- * return 1(0) if the specified bit position in value is set(clear)
- */
- bool bitPosition(uint16_t value, uint16_t position)
- {
- if ((value & (1 << position)))
- return 1;
- return 0;
- }
-
- /*
- * ======== eusci_calcBaudDividers ========
- * computes the eUSCI_UART register settings for a given clock and baud rate
- *
- * UCOS16: the oversampling bit (0 or 1)
- * UCBRx: the Baud Rate Control Word
- * UCFx: the First modulation stage select (UCBRFx)
- * UCSx: the Second modulation stage select (UCBRSx)
- * maxAbsError: the maximum TX error for the register setting above
- *
- * The first four field names match the names used in Table 18-5,
- * "Recommended Settings for Typical Crystals and Baudrates", of the
- * MSP430FR57xx Family User's Guide (SLAU272A).
- */
-
- void eusci_calcBaudDividers(eUSCI_UART_ConfigV1 *uart_config, uint32_t baudRate) //固件库v3_40_01_02
-
-
- {
- float maxAbsErrorInByte;
- float minAbsError;
- float error;
- uint8_t ii;
- uint16_t jj;
- uint16_t NN;
- uint32_t count;
- uint32_t clockRate;
-
- if (!uart_config || !baudRate) //传参错误 退出函数
- {
- //uart_warning_led(); //闪烁错误指示灯10次
- return;
- }
-
- if (uart_config->selectClockSource == EUSCI_A_UART_CLOCKSOURCE_SMCLK)
- clockRate = MAP_CS_getSMCLK();
- else if (uart_config->selectClockSource == EUSCI_A_UART_CLOCKSOURCE_ACLK)
- clockRate = MAP_CS_getACLK();
- else
- {
- uart_config->selectClockSource = EUSCI_A_UART_CLOCKSOURCE_SMCLK;
- clockRate = MAP_CS_getSMCLK();
- }
- if (baudRate > clockRate) //判断波特率是否大于时钟频率 是则退出函数
- {
- //uart_warning_led(); //闪烁错误指示灯10次
- return;
- }
- //var result = {UCOS16 : 0, UCBRx : 0, UCFx : 0, UCSx : 0, maxAbsError : 0};
-
- NN = (uint16_t)((float)clockRate / (float)baudRate); //应该是不需要floor
-
- minAbsError = 100000;
- for (jj = 0; jj <= 255; jj++)
- {
-
- maxAbsErrorInByte = 0;
- count = 0;
- for (ii = 0; ii <= 10; ii++)
- {
- count += NN + bitPosition(jj, 7 - (ii % 8));
-
- //error = (ii + 1) * baudPeriod - count * clockPeriod;
- error = (ii + 1) / (float)baudRate - count / (float)clockRate; //为了减少变量,改为此代码
-
- if (error < 0)
- error = -error;
-
- if (error > maxAbsErrorInByte)
- maxAbsErrorInByte = error;
- }
- if (maxAbsErrorInByte - minAbsError < -7.3e-12f) //这里就是“已知问题”
- {
- minAbsError = maxAbsErrorInByte;
- uart_config->secondModReg = jj;
- }
- }
-
- if (NN < 20)
- {
- uart_config->overSampling = 0;
- uart_config->clockPrescalar = NN;
- uart_config->firstModReg = 0;
- }
- else
- {
- uart_config->overSampling = 1;
- uart_config->clockPrescalar = (uint16_t)((float)NN / 16.0f); //应该是不需要floor
- uart_config->firstModReg = NN - (uart_config->clockPrescalar * 16);
- }
- //return minAbsError * baudRate * 100;
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。