江科大UART串口通讯hal库实现
hal库相关库函数
初始化结构体
typedef struct
{uint32_t BaudRate; /*波特率设置*/uint32_t WordLength; /*字长设置*/uint32_t StopBits; /*停止位设置 */uint32_t Parity; /*奇偶校验位设置*/uint32_t Mode; /*接受发送模式设置*/uint32_t HwFlowCtl; /*硬件流控制设置*/uint32_t OverSampling; /*采样速度设置*/
} UART_InitTypeDef;
typedef struct __UART_HandleTypeDef
{USART_TypeDef *Instance; /*选择的串口外设地址*/UART_InitTypeDef Init; /*串口初始化*/const uint8_t *pTxBuffPtr; /*发送数据的缓冲区*/uint16_t TxXferSize; /*发送数据大小*/__IO uint16_t TxXferCount; /*用于记录还剩余的要发送的数据量*/uint8_t *pRxBuffPtr; /*接收数据缓冲区*/uint16_t RxXferSize; /*接收数据大小*/__IO uint16_t RxXferCount; /*用于记录还剩余的要接收的数据量*/__IO HAL_UART_RxTypeTypeDef ReceptionType; /*标识当前 UART 接收模式的成员变量。它决定了 UART 如何处理接收到的数据,比如说中断处理或者DMA处理*/__IO HAL_UART_RxEventTypeTypeDef RxEventType; /*接收事件类型*/DMA_HandleTypeDef *hdmatx; /*发送功能DMA句柄*/DMA_HandleTypeDef *hdmarx; /*接受功能DMA句柄*/HAL_LockTypeDef Lock; /*状态锁存*/__IO HAL_UART_StateTypeDef gState; /*它的主要作用是存储当前 UART 的状态,方便在程序的不同部分查询 UART 的工作状态global state */__IO HAL_UART_StateTypeDef RxState; /*接收状态*/__IO uint32_t ErrorCode; /*错误标志位*/#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)void (* TxHalfCpltCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Tx Half Complete Callback */void (* TxCpltCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Tx Complete Callback */void (* RxHalfCpltCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Rx Half Complete Callback */void (* RxCpltCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Rx Complete Callback */void (* ErrorCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Error Callback */void (* AbortCpltCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Abort Complete Callback */void (* AbortTransmitCpltCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Abort Transmit Complete Callback */void (* AbortReceiveCpltCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Abort Receive Complete Callback */void (* WakeupCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Wakeup Callback */void (* RxEventCallback)(struct __UART_HandleTypeDef *huart, uint16_t Pos); /*!< UART Reception Event Callback */void (* MspInitCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Msp Init callback */void (* MspDeInitCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Msp DeInit callback */
#endif /* USE_HAL_UART_REGISTER_CALLBACKS */} UART_HandleTypeDef;
FE帧错误,ORE过载错误,NE噪声错误
初始化相关函数
初始化,半双工,初始化 LIN 外设,多进程,恢复缺省配置
HAL_StatusTypeDef HAL_UART_Init(UART_HandleTypeDef *huart);
HAL_StatusTypeDef HAL_HalfDuplex_Init(UART_HandleTypeDef *huart);
HAL_StatusTypeDef HAL_LIN_Init(UART_HandleTypeDef *huart, uint32_t BreakDetectLength);
HAL_StatusTypeDef HAL_MultiProcessor_Init(UART_HandleTypeDef *huart, uint8_t Address, uint32_t WakeUpMethod);
HAL_StatusTypeDef HAL_UART_DeInit(UART_HandleTypeDef *huart);
void HAL_UART_MspInit(UART_HandleTypeDef *huart);
void HAL_UART_MspDeInit(UART_HandleTypeDef *huart);
发送接收相关函数 ,普通收发,中断收发,DMA收发,以及DMA暂停,DMA恢复,DMA停止
其中DMAResume得在DMAPause后面.
HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size, uint32_t Timeout);
HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout);
HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_UART_DMAPause(UART_HandleTypeDef *huart);
HAL_StatusTypeDef HAL_UART_DMAResume(UART_HandleTypeDef *huart);
HAL_StatusTypeDef HAL_UART_DMAStop(UART_HandleTypeDef *huart);
扩展部分
HAL_StatusTypeDef HAL_UARTEx_ReceiveToIdle(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint16_t *RxLen,uint32_t Timeout);
HAL_StatusTypeDef HAL_UARTEx_ReceiveToIdle_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_UARTEx_ReceiveToIdle_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
扩展部分是串口不断接收数据,直到空闲状态,有三种不同的接受方式
串口接收的事件获取
串口中止 UART 通信的函数,它可以同时中止发送和接收操作。
串口中止发送,中止接收,中止中断,中止发送中断,中止接受中断。
HAL_UART_RxEventTypeTypeDef HAL_UARTEx_GetRxEventType(UART_HandleTypeDef *huart);
HAL_StatusTypeDef HAL_UART_Abort(UART_HandleTypeDef *huart);
HAL_StatusTypeDef HAL_UART_AbortTransmit(UART_HandleTypeDef *huart);
HAL_StatusTypeDef HAL_UART_AbortReceive(UART_HandleTypeDef *huart);
HAL_StatusTypeDef HAL_UART_Abort_IT(UART_HandleTypeDef *huart);
HAL_StatusTypeDef HAL_UART_AbortTransmit_IT(UART_HandleTypeDef *huart);
HAL_StatusTypeDef HAL_UART_AbortReceive_IT(UART_HandleTypeDef *huart);
串口的收发
根据江科大的串口设计来配置我们的CubeMX
首先使用UART1,波特率为9600,非硬件流控制,发送接收模式都要,一位停止位,八位字长,不需要奇偶校验位,开启中断,抢占优先级和响应优先级都为1,
创建完成后我们就可以完成串口的收发了,我们使用正点原子的串口调试工具
HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size, uint32_t Timeout);
HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout);
这两个代码在while循环里面轮询收发数据,比如接收发送3位数据abc,你会发现少接收了一位a只接收到bc且发送的也是bc,数组里面a的位置我们显示出来是0D,也就是回车键的ascll码值。
这是什么原因呢?
原因在这里,他加入了回车换行导致我们的代码a变成了回车
所以对于串口工具的了解也是有必要的。
但是这是阻塞式的收发,超时时间都是1s,也就是我不发生数据,就会在接受数据函数这里卡住整整1s的时间,这对于我们的单片机程序是致命的,1s可以让他做非常多的事情了。所以我们通常使用中断收发模式。
HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
只有触发中断,才进行一次数据的接受和发送,这样就能大大的减少我们在串口收发里面花费的时间,且主程序还能正常运行,不被干扰。
我们在while循环前面进行中断的接收打开,当串口助手发送数据的时候,触发接收中断,接收到数据并进入接收中断函数里面,如果还要继续接收别的数据,我们就得在接受中断函数里面再次开启接受中断。对于接受和发送,我们得对他们进行分离处理,让他们各司其职,比如说最好不要在接收中断函数里面进行数据发送,数据发送不出来且可能和接收函数有冲突导致二者都不能正常工作。
__HAL_UART_GET_FLAG()
我们可以通过get_flag宏定义来判断中断标志位,也可以和江科的代码大一样实现串口的收发,但是那个收发函数太麻烦了,还需要我们手动判断标志位,清除标志位,发送函数也是由一位字长数据发送函数嵌套得到的字符串发送函数。而hal库直接给我们提供好了这么多便捷的串口收发函数,比如轮询式最普通的收发函数,还给我们添加了超时保护,所以我觉得在hal库这里对于江科大的串口收发函数的复现是意义不大的。
uint8_t zfc[20];//收发数组
int main(void)
{OLED_Init();//初始化OLED显示屏HAL_Init();SystemClock_Config();MX_GPIO_Init();MX_USART1_UART_Init();OLED_ShowString(1, 1, "RxData:");HAL_UART_Receive_IT(&huart1,zfc,3);//开启中断接受while (1){OLED_ShowHexNum(1,8,zfc[0],2);//显示接收到的值OLED_ShowHexNum(1,11,zfc[1],2);OLED_ShowHexNum(1,14,zfc[2],2);HAL_UART_Transmit(&huart1,zfc,3,1000);//发送接收到的值HAL_Delay(1000);//延时1s,不然会眼花缭乱的}
}void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){if(huart == &huart1){
// OLED_ShowString(2,1,"success");//测试中断是否成功接收HAL_UART_Receive_IT(&huart1,zfc,3);//重新启动中断接受}
}
CubeMx创建的文件注释部分太多了,我把注释部分删掉了,这样所有先关代码就能全部显示在一个界面上了。
我这里是固定长度的收发,如果要实现字符串收发,也可以用字符串相关函数,把固定长度修改成字符串的长度即可(应该是str_len函数)