赞
踩
文章目录
这个暑假参加了电赛,做的是飞机题,因此经常需要使用到串口通信,完成各个模块之间的通信。但是,在使用串口的时候却发现很多的问题,因此这里记录一下一些串口通信方式。主要参考匿名飞控的串口的通信代码。
首先,先给出匿名飞控之间的串口通信的协议。
由上图可知,匿名飞控之间的串口通信都是数据长度已知的。
下面开始分析代码
首先是串口的配置(STM32F103C8T6)
- //USART1
- void DrvUart1Init(u32 br_num)
- {
- USART_InitTypeDef USART_InitStructure;
- USART_ClockInitTypeDef USART_ClockInitStruct;
- NVIC_InitTypeDef NVIC_InitStructure;
- GPIO_InitTypeDef GPIO_InitStructure;
-
- USART_StructInit(&USART_InitStructure);
-
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE); //使能USART1,GPIOA时钟
-
-
- //Usart1 NVIC 配置
- NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级3
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
- NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
-
- // GPIO_PinAFConfig(GPIOB, GPIO_PinSource10, GPIO_AF_USART3);
- // GPIO_PinAFConfig(GPIOB, GPIO_PinSource11, GPIO_AF_USART3);
-
- //USART1_TX GPIOA.9
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
- GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.9
-
- //USART1_RX GPIOA.10初始化
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
- GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10
-
-
- USART_InitStructure.USART_BaudRate = br_num;
- USART_InitStructure.USART_WordLength = USART_WordLength_8b;
- USART_InitStructure.USART_StopBits = USART_StopBits_1;
- USART_InitStructure.USART_Parity = USART_Parity_No;
- USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
- USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
-
- USART_ClockInitStruct.USART_Clock = USART_Clock_Disable;
- USART_ClockInitStruct.USART_CPOL = USART_CPOL_Low;
- USART_ClockInitStruct.USART_CPHA = USART_CPHA_2Edge;
- USART_ClockInitStruct.USART_LastBit = USART_LastBit_Disable;
-
- USART_Init(USART1, &USART_InitStructure);
- USART_ClockInit(USART1, &USART_ClockInitStruct);
-
- USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
-
- USART_Cmd(USART1, ENABLE);
- }
-
-
- u8 Tx1Buffer[256];
- u8 Tx1Counter = 0;
- u8 count1 = 0;
- void DrvUart1SendBuf(unsigned char *DataToSend, u8 data_num)
- {
- u8 i;
- for (i = 0; i < data_num; i++)
- {
- Tx1Buffer[count1++] = *(DataToSend + i);
- }
-
- if (!(USART1->CR1 & USART_CR1_TXEIE))
- {
- USART_ITConfig(USART1, USART_IT_TXE, ENABLE); //打开发送中断
- }
- }
- u8 U1RxDataTmp[100];
- u8 U1RxInCnt = 0;
- u8 U1RxoutCnt = 0;
- void drvU1GetByte(u8 data)
- {
- U1RxDataTmp[U1RxInCnt++] = data;
- if(U1RxInCnt >= 100)
- U1RxInCnt = 0;
- }
- void drvU1DataCheck(void)
- {
- while(U1RxInCnt!=U1RxoutCnt)
- {
- U1GetOneByte(U1RxDataTmp[U1RxoutCnt++]);
- if(U1RxoutCnt >= 100)
- U1RxoutCnt = 0;
- }
- }
- void Usart1_IRQ(void)
- {
- u8 com_data;
-
- if (USART1->SR & USART_SR_ORE) //ORE中断
- {
- com_data = USART1->DR;
- }
- //接收中断
- if (USART_GetITStatus(USART1, USART_IT_RXNE))
- {
- USART_ClearITPendingBit(USART1, USART_IT_RXNE); //清除中断标志
- Res_Data = USART1->DR;
-
- drvU1GetByte(com_data);
- }
- //发送(进入移位)中断
- if (USART_GetITStatus(USART1, USART_IT_TXE))
- {
- USART1->DR = Tx1Buffer[Tx1Counter++]; //写DR清除中断标志
- if (Tx1Counter == count1)
- {
- USART1->CR1 &= ~USART_CR1_TXEIE; //关闭TXE(发送中断)中断
- }
- }
- }
-
- void USART1_IRQHandler(void)
- {
- Usart1_IRQ();
- }
-
- //USART3
- void DrvUart3Init(u32 br_num)
- {
- USART_InitTypeDef USART_InitStructure;
- USART_ClockInitTypeDef USART_ClockInitStruct;
- NVIC_InitTypeDef NVIC_InitStructure;
- GPIO_InitTypeDef GPIO_InitStructure;
-
- USART_StructInit(&USART_InitStructure);
-
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
-
-
- NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
- NVIC_Init(&NVIC_InitStructure);
-
- // GPIO_PinAFConfig(GPIOB, GPIO_PinSource10, GPIO_AF_USART3);
- // GPIO_PinAFConfig(GPIOB, GPIO_PinSource11, GPIO_AF_USART3);
-
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_Init(GPIOB, &GPIO_InitStructure);
-
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_Init(GPIOB, &GPIO_InitStructure);
-
-
- USART_InitStructure.USART_BaudRate = br_num;
- USART_InitStructure.USART_WordLength = USART_WordLength_8b;
- USART_InitStructure.USART_StopBits = USART_StopBits_1;
- USART_InitStructure.USART_Parity = USART_Parity_No;
- USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
- USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
-
- USART_ClockInitStruct.USART_Clock = USART_Clock_Disable;
- USART_ClockInitStruct.USART_CPOL = USART_CPOL_Low;
- USART_ClockInitStruct.USART_CPHA = USART_CPHA_2Edge;
- USART_ClockInitStruct.USART_LastBit = USART_LastBit_Disable;
-
- USART_Init(USART3, &USART_InitStructure);
- USART_ClockInit(USART3, &USART_ClockInitStruct);
-
- USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);
-
- USART_Cmd(USART3, ENABLE);
- }
-
- u8 Tx3Buffer[256];
- u8 Tx3Counter = 0;
- u8 count3 = 0;
- void DrvUart3SendBuf(unsigned char *DataToSend, u8 data_num)
- {
- u8 i;
- for (i = 0; i < data_num; i++)
- {
- Tx3Buffer[count3++] = *(DataToSend + i);
- }
- if (!(USART3->CR1 & USART_CR1_TXEIE))
- {
- USART_ITConfig(USART3, USART_IT_TXE, ENABLE); //打开发送中断
- }
- }
- u8 U3RxDataTmp[100];
- u8 U3RxInCnt = 0;
- u8 U3RxoutCnt = 0;
- void drvU3GetByte(u8 data)
- {
- U3RxDataTmp[U3RxInCnt++] = data;
- if(U3RxInCnt >= 100)
- U3RxInCnt = 0;
- }
- void drvU3DataCheck(void)
- {
- while(U3RxInCnt!=U3RxoutCnt)
- {
- U3GetOneByte(U3RxDataTmp[U3RxoutCnt++]);
- if(U3RxoutCnt >= 100)
- U3RxoutCnt = 0;
- }
- }
- void Usart3_IRQ(void)
- {
- u8 com_data;
-
- if (USART3->SR & USART_SR_ORE) //ORE中断
- com_data = USART3->DR;
-
- //接收中断
- if (USART_GetITStatus(USART3, USART_IT_RXNE))
- {
- USART_ClearITPendingBit(USART3, USART_IT_RXNE); //清除中断标志
- com_data = USART3->DR;
- drvU3GetByte(com_data);
- }
- //发送(进入移位)中断
- if (USART_GetITStatus(USART3, USART_IT_TXE))
- {
- USART3->DR = Tx3Buffer[Tx3Counter++]; //写DR清除中断标志
- if (Tx3Counter == count3)
- {
- USART3->CR1 &= ~USART_CR1_TXEIE; //关闭TXE(发送中断)中断
- }
- }
- }
- void DrvUartDataCheck(void)
- {
- drvU3DataCheck();
- drvU1DataCheck();
- }
- void USART3_IRQHandler(void)
- {
- Usart3_IRQ();
- }
需要注意的事,匿名飞控的Usart3_IRQ();Usart1_IRQ();都是封装好的串口处理函数,使用时,必须把它们放到对应的中断函数处理函数void USART3_IRQHandler(void),否则程序会卡死。同时,将void DrvUartDataCheck(void)这个函数需要放入1ms的中断(建议用一个定时器作为系统的定时,1ms进入1次),这样串口收发的数据就会1ms处理一次。
void DrvUartDataCheck(void)中调用drvU3DataCheck()就是对应串口的数据接收处理的部分。
- void drvU3DataCheck(void)
- {
- while(U3RxInCnt!=U3RxoutCnt)
- {
- U3GetOneByte(U3RxDataTmp[U3RxoutCnt++]);
- if(U3RxoutCnt >= 100)
- U3RxoutCnt = 0;
- }
- }
drvU3DataCheck()中调用了用户自定义的串口接收函数U3GetOneByte(),U3GetOneByte可以通过宏定义修改为自定义函数名。例如下图
同时,这个时候自己就可以在另外的.c文件中定义自己的函数接收函数 ,下面以OPENMV_GetOneByte为例。
下面为代码
- /***********接受数据定义区***************/
- #define BB_data0 opmv.lt.shape_flag
- #define BB_data1 opmv.lt.err_X
- #define BB_data2 opmv.lt.shape_cx
- #define BB_data3 opmv.lt.err_Dis
- #define BB_data4 opmv.lt.ultrasonic_distance
- #define BB_data5 opmv.lt.fire_flag
- #define BB_data6 opmv.lt.color_flag
- #define BB_data7 opmv.lt.y_vel_out//openmv x方向速度
- #define BB_data8 opmv.lt.x_vel_out//超声波前后 控制速度
-
-
- #define CC_data0 opmv.lt.found_flag//光源寻找到的标志位
- #define CC_data1 opmv.lt.red_cx
- #define CC_data2 opmv.lt.red_cy
- #define CC_data3 opmv.lt.green_pid_vel_v
- #define CC_data4 opmv.lt.red_pid_vel_v
- #define CC_data5 opmv.lt.ultrasonic_distance
- #define CC_data6 opmv.lt.ultrasonic_vel_v
- #define CC_data7 opmv.lt.y_vel_out//
- #define CC_data8 opmv.lt.x_vel_out
-
- #define DD_data0 opmv.lt.start_flag
- #define DD_data1 opmv.lt.start_flag2
- #define DD_data2 nouse
- #define DD_data3 nouse
- #define DD_data4 nouse
- #define DD_data5 nouse
- #define DD_data6 nouse
- #define DD_data7 nouse
- #define DD_data8 nouse
-
-
-
-
-
-
- /***********接受数据处理***************/
- static void OPENMV_DataAnl(uint8_t *data, uint8_t len1)
- {
- u8 check_sum3 = 0, check_sum4 = 0;
- if (*(data + 3) != (len1 - 6)) //判断数据长度是否正确
- return;
- for (u8 i = 0; i < len1 - 2; i++)
- {
- check_sum3 += *(data + i);
- check_sum4 += check_sum3;
- }
- if ((check_sum3 != *(data + len1 - 2)) || (check_sum4 != *(data + len1 - 1))) //判断sum校验
- return;
- //================================================================================
-
- if(*(data + 2) == 0XBB)//底面的openmv
- {
- BB_data0 = *(data + 4)<<8|*(data + 5);//opmv.lt.shape_flag
- BB_data1 = *(data + 6)<<8|*(data + 7);//opmv.lt.color_flag
- BB_data2 = *(data + 8)<<8|*(data + 9);//opmv.lt.shape_cx
- BB_data3 = *(data + 10)<<8|*(data + 11);//opmv.lt.shape_cy
- BB_data4 = *(data + 12)<<8|*(data + 13);//Nouse
- BB_data5 = *(data + 14)<<8|*(data + 15);//Nouse
- BB_data6 = *(data + 16)<<8|*(data + 17);//Nouse
- BB_data7 = *(data + 18)<<8|*(data + 19);//opmv.lt.shape_cy
- BB_data8 = *(data +20)<<8|*(data + 21);//opmv.lt.shape_cy
-
- }
- else if(*(data + 2) == 0XCC)//顶面的openmv
- {
-
- CC_data0 = *(data + 4)<<8|*(data + 5);//Nouse
- CC_data1 = *(data + 6)<<8|*(data + 7);//Nouse
- CC_data2 = *(data + 8)<<8|*(data + 9);//Nouse
- // CC_data3 = *(data + 10)<<8|*(data + 11);//Nouse
- // CC_data4 = *(data + 12)<<8|*(data + 13);//Nouse
- // CC_data5 = *(data + 14)<<8|*(data + 15);//Nouse
- // CC_data6 = *(data + 16)<<8|*(data + 17);//Nouse
- CC_data7 = *(data + 18)<<8|*(data + 19);//Nouse
- CC_data8 = *(data +20)<<8|*(data + 21);//Nouse
- }
- else if(*(data + 2) == 0XDD)//zigbee数传
- {
-
- DD_data0 = *(data + 4);//opmv.lt.start_flag
- DD_data1 = *(data + 5);//Nouse
- // DD_data2 = *(data + 8)<<8|*(data + 9);//Nouse
- // DD_data3 = *(data + 10)<<8|*(data + 11);//Nouse
- // DD_data4 = *(data + 12)<<8|*(data + 13);//Nouse
- // DD_data5 = *(data + 14)<<8|*(data + 15);//Nouse
- // DD_data6 = *(data + 16)<<8|*(data + 17);//Nouse
- // DD_data7 = *(data + 18)<<8|*(data + 19);//Nouse
- // DD_data8 = *(data +20)<<8|*(data + 21);//Nouse
- }
- }
-
-
- # define HW_TYPE 0x61
- /***********接受数据解析,参考匿名飞控通信协议***************/
- void OPENMV_GetOneByte(uint8_t data)
- {
- static u8 _data_len = 0, _data_cnt = 0;
- static u8 rxstate = 0;
-
- if (rxstate == 0 && data == 0xAA)
- {
- rxstate = 1;
- uart3_datatemp[0] = data;
- }
- else if (rxstate == 1 && (data == HW_TYPE || data == HW_ALL))
- {
- rxstate = 2;
- uart3_datatemp[1] = data;
- }
- else if (rxstate == 2)
- {
- rxstate = 3;
- uart3_datatemp[2] = data;
- }
- else if (rxstate == 3 && data < 250)
- {
- rxstate = 4;
- uart3_datatemp[3] = data;
- _data_len = data;
- _data_cnt = 0;
- }
- else if (rxstate == 4 && _data_len > 0)
- {
- _data_len--;
- uart3_datatemp[4 + _data_cnt++] = data;
- if (_data_len == 0)
- rxstate = 5;
- }
- else if (rxstate == 5)
- {
- rxstate = 6;
- uart3_datatemp[4 + _data_cnt++] = data;
- }
- else if (rxstate == 6)
- {
- rxstate = 0;
- uart3_datatemp[4 + _data_cnt] = data;
- // DT_data_cnt = _data_cnt+5;
- //
- OPENMV_DataAnl(uart3_datatemp, _data_cnt + 5); //
- }
- else
- {
- rxstate = 0;
- }
- }
void OPENMV_GetOneByte(uint8_t data)就是按照匿名协议进行数据接收,接受完一帧数据后调用OPENMV_DataAnl(uart3_datatemp, _data_cnt + 5)这个函数,进行数据解析,通过自己的宏定义与数据对应上,这里采用宏定义主要是为了与openmv那边的数据位对应上(方便与视觉队友对接),同时在1对多的通信也比较容易区分。
- from pyb import UART
-
- uart = UART(3,500000)
-
-
- class Receive(object):
- uart_buf = []
- _data_len = 0
- _data_cnt = 0
- state = 0
- R=Receive()
-
-
- class Ctrl(object):
- Data1 = 0
- Data2 = 0
- Data3 = 0
- Data4 = 0
- Data5 = 0
- Data6 = 0
- Data7 = 0
- Data8 = 0
- Data9 = 0
- Data10 = 0
- IsDebug = 1
- T_ms = 0
- Ctr=Ctrl()
-
-
- def UartSendData(Data):
- if uart.write(Data)==None:
- print('send error')
-
-
- def ReceiveAnl(data_buf):
- Ctr.Data1=data_buf[2]
- Ctr.Data2=data_buf[3]
- Ctr.Data3=data_buf[4]
- Ctr.Data4=data_buf[5]
- Ctr.Data5=data_buf[6]
- Ctr.Data6=data_buf[7]
- Ctr.Data7=data_buf[8]
- Ctr.Data8=data_buf[9]
- Ctr.Data9=data_buf[10]
- Ctr.Data10=data_buf[11]
-
-
- def ReceivePrepare(data):
- if R.state==0:
- if data == 0xAA:
- R.uart_buf.append(data)
- R.state = 1
- else:
- R.state = 0
- elif R.state==1:
- if data == 0x32:
- R.uart_buf.append(data)
- R.state = 2
- else:
- R.state = 0
- elif R.state==2:
-
- R.uart_buf.append(data)
- R.state = 3
- elif R.state==3:
-
- R.state = 4
- R.uart_buf.append(data)
- elif R.state==4:
-
- R.uart_buf.append(data)
- R.state = 5
- elif R.state==5:
-
- R.state = 6
- R.uart_buf.append(data)
- elif R.state==6:
-
- R.uart_buf.append(data)
- R.state = 7
- elif R.state==7:
-
- R.state = 8
- R.uart_buf.append(data)
- elif R.state==8:
-
- R.state = 9
- R.uart_buf.append(data)
- elif R.state==9:
-
- R.state = 10
- R.uart_buf.append(data)
- elif R.state==10:
-
- R.state = 11
- R.uart_buf.append(data)
- elif R.state==11:
-
- R.state = 12
- R.uart_buf.append(data)
- elif R.state==12:
- if data == 0xdd:
- R.state = 0
- R.uart_buf.append(data)
- ReceiveAnl(R.uart_buf)
- R.uart_buf=[]#清空缓冲区,准备下次接收数据
- else:
- R.state = 0
- else:
- R.state = 0
-
-
- def UartReadBuffer():
- i = 0
- Buffer_size = uart.any()
- while i<Buffer_size:
- ReceivePrepare(uart.readchar())
- i = i + 1
-
-
-
- def UserDataPack(data0,data1,data2,data3,data4,data5,data6,data7,data8):
- UserData=bytearray([0xAA,0x61,0xBB,0x00
- ,data0,data1,data2,data3,data4,data5,data6,data7,data8
- ,0x00,0x00])
- lens = len(UserData)
- UserData[3] = lens-6;
- i = 0
- sum = 0
- sum1 = 0
- while i<(lens-2):
- sum = sum + UserData[i]
- sum1 = sum1 + sum
- i = i+1
- UserData[lens-2] = sum;
- UserData[lens-1] = sum1;
- return UserData
这里也是参照匿名openmv的代码,这边的代码就参考上图进行修改。但是注意openmv在接受数据的时候存在丢包的现象,目前还不清楚为什么。飞控这边为了减少处理的压力,把一部分的PID运算放到了Openmv端,但是在初始化PID参数的时候发现经常会有某个PID无法传参,存在丢包现象。因此,为保险起见,飞控在传输数据到openmv时,通常是连续发个几百毫秒。
以上便是数据长度已知的串口通信方式,之后在运用的时候可以参照这种方式修改,调了一个暑假这种方式还是挺稳定的。
- void Uart_Send_Str(unsigned char * p)
- {
- while(*p)
- {
- Uart_Send_byte(*p++);
- }
- }
值得注意的事,进行串口发送的时候,采用上述代码的方式一旦数据有0便会结束,调用void DrvUart1SendBuf(unsigned char *DataToSend, u8 data_num),这个函数进行发送的时候就不会。
UWB的通信协议
UWB配置完成后会,自动按照上述例子将数据发送过来,按照字符进行发送,数据不定长。当时比赛的时候是第一次用这个UWB,虽然协议很简单,但是为了读UWB的数据也花费了一个下午的时间。
这里也是采用匿名飞控的程序的数据接收,但是数据解析函数有些不相同。
- #define UART2_BUFFER_SIZE 100 // 假设uart2_datatemp的大小为100
- void UWB_GetOneByte(char data)
- {
- static u8 rxstate_2 = 0;
- static u8 i = 0;
-
- // 增加数据长度检查,防止数据长度超出缓冲区大小
- if (i >= UART2_BUFFER_SIZE - 1)
- {
- // 缓冲区已满,进行错误处理或清空操作
- rxstate_2 = 0;
- i = 0;
- // 这里可以根据实际情况进行处理,比如错误提示、丢弃当前数据等
- return;
- }
-
- if (rxstate_2 == 0 && data == '[')
- {
- rxstate_2 = 1;
- uart2_datatemp[0] = data;
- }
- else if (rxstate_2 == 1)
- {
- if (data != ']')
- {
- i++;
- uart2_datatemp[i] = data;
- }
- else
- {
- i++;
- uart2_datatemp[i] = data;
- // 增加对数据长度的检查,防止传递错误的数据长度
- if (i + 2 <= UART2_BUFFER_SIZE)
- {
- UWB_Data_Anl(uart2_datatemp, i + 2);
- }
- // 处理完一组数据后,重置接收状态和缓冲区
- rxstate_2 = 0;
- i = 0;
- // 清空缓冲区
- // memset(uart2_datatemp, 0, sizeof(uart2_datatemp));
- }
- }
- else
- {
- // 处理未知状态,重置接收状态和缓冲区
- rxstate_2 = 0;
- i = 0;
- // 清空缓冲区
- //memset(uart2_datatemp, 0, sizeof(uart2_datatemp));
- }
- }
注意这这rxstate_2、i两个变量在接受完成或者数据接收错误的时候都要清0。
目前这就更新到这里,以后在遇到坑再过来填!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。