热度 1
2024-12-4 15:23
216 次阅读|
0 个评论
将串口接收配置为 DMA方式,DMA 使用 DMA_CIRCULAR 模式工作。串口接收的数据实际上构成循环队列。 定义一个结构Comm_typedef 结构体中包含指向接收到的第一字节位置chrchr,最后一字节位置 lastchr 接收缓冲区长度 rlen 指向接收缓冲区指针 *pRxBuf 指向使用的串口句柄指针*pUart, 指向使用的DMA串口接收句柄指针 *pRx 指向DMA串口发送指针*pTx 检查接收到的字节数的函数 CheckRsv 和串口处理函数 Parse #ifndef __COMM_H #define __COMM_H typedef struct { uint16_t curchr; uint16_t lastchr; uint16_t rlen; uint8_t *pRxBuf; UART_HandleTypeDef *pUart; DMA_HandleTypeDef *pRx; DMA_HandleTypeDef *pTx; uint8_t (* Parse)(struct stComm *p); uint8_t (* CheckRsv)(struct stComm *p); } Comm_typedef; uint8_t UartCheckRsv(Comm_typedef *p); uint8_t SerialParse(Comm_typedef *p); void Serial_Control_Init(Comm_typedef *pcom); #endif // 完成串口的配置后,可以得到 uart 及 dma 操作句柄 extern UART_HandleTypeDef huart2; extern DMA_HandleTypeDef hdma_usart2_tx; extern DMA_HandleTypeDef hdma_usart2_rx; // 定接收缓冲区 长度及缓冲区 #define RXBUFLEN 32 uint8_t UARTRxBuf ; // 检查是否接收到数据的函数,使用DMA数据计数器与DMA缓冲区长度的差得到lastchr的位置,如果lastchr 不等于 chrchr则说明收到数据。 uint8_t UartCheckRsv(Comm_typedef *p) { CNDTR; // NDTR lastchr) return 1; else return 0; } uint8_t SerialParse(Comm_typedef *p); // 串口控制初始化函数,将一个初始化一个 Comm_typedef 类型 void Serial_Control_Init(Comm_typedef *pcom) { pUart = &huart2; rlen = RXBUFLEN; lastchr = 0; curchr = 0; pRxBuf = UARTRxBuf; pRx = &hdma_usart2_rx; pTx = &hdma_usart2_tx; CheckRsv = UartCheckRsv; Parse = SerialParse; } 实际使用时,先定义好Comm_typedef 类型 Comm_typedef CntlComm; 然后初始化 Serial_Control_Init(&CntlComm); 启动串口DMA方式接收。 HAL_UART_Receive_DMA(CntlComm.pUart,CntlComm.pRxBuf,CntlComm.rlen); // 程序中定时执行CntlComm.CheckRsv(&CntlComm)检查是否接收到数据,如果收到则运行串口解析程序。 这个定时时间大于100ms为宜。不要过快。 if(CntlComm.CheckRsv(&CntlComm)) { CntlComm.Parse(&CntlComm); } // 关于解析程序,需要依据自行定义的串口通信协议编写。这里有一个简单的协议。数据格式如下: 包头 数据内容 包尾 SET XXX \r\n GET XXX \r\n // 定义一个解析程序如下:在解析程序中查找合法的字段,先找包头,然后找包尾。找到合法的包后,作出交互处理。同时修改curchr 跳过已经处理的数据或无效数据。 #define MAXCMDLEN 30 uint8_t SerialParse(Comm_typedef *p){ static uint8_t tempstr ; int8_t sync_idx = -1,tail_idx = -1, j; int16_t i; static uint8_t cmd ; curchr; lastchr){ //Scan to last chr to find head word rlen] == 'T')) rlen] == 'T'))){ sync_idx = i; /* first sync byte is found */ break; } else{ rlen - 1))? 0 : i + 1; } } if(sync_idx != -1){ // head found j = 0; lastchr){ pRxBuf ; rlen - 1)) break; rlen] == '\n')){ tail_idx = i; break; } else{ rlen - 1))? 0 : i + 1; } } cmd = '\n';cmd =0; if(tail_idx != -1){ // tail found if(strstr((char *)cmd,"SETTIME") != NULL){ uint8_t hour = ((cmd -'0')*10) + (cmd - '0'); uint8_t minute = ((cmd -'0')*10) + (cmd - '0'); uint8_t second = ((cmd -'0')*10) + (cmd - '0'); DS1302_SetTime(hour,minute,second); sprintf((char *)tempstr,"Write time\r\n"); pUart,tempstr,strlen((char *)tempstr)); } else if(strstr((char *)cmd,"GETTIME") != NULL){ uint8_t year,month,day,hour,minute,second; DS1302_GetDate(&year, &month, &day); DS1302_GetTime(&hour, &minute, &second); sprintf((char *)tempstr,"%d.%d.%d. %2d:%02d:%02d\r\n",year,month,day,hour,minute,second); pUart,tempstr,strlen((char *)tempstr),1000); } curchr = tail_idx + 2; } // Finish one cmd process else { // tail not found lastchr; return 0; } } else { // head not found lastchr; return 0; } return 1; } 如果有多个串口,可以为每个串口控制定义一个 Comm_typedef 类型。分别进行初始化。这个可以使用近于一致的操作。并实现各自的独立性,互不影响。