今天要开始学习串口数据的一个收和发
很多单片机存在多个串口收发,比如wifi开发等,都需要通过串口来进行数据交互。
首先需要了解下并行通信和串行通信:这两种方式大多都是用来外部和微处理器进行通信的主要方式。
其中,并行就是传输速度块,但是占用资源大,需要引脚比较多
串行的话,占用资源和引脚都比较少,但是传输速度比较慢。
接下来看看,串行通信种存在三种模式:单工,半双工,全双工
单工就是:只有一个方向,要么只能发送或者只能接受
半双工:就是可以接收也可以发送,但是不能同时进行。需要调整模式在下一个时间段进行接收或者发送的动作。比较典型的就是RS450这种总线
全双工:就是同时进行,比较牛逼。基本现在都是全双工。
然后看看啥叫异步串行通信:通信双方在没有同步时钟的前提下,将一个字符按位进行传输的通信方式。一般来说没有同步时钟,很难准确接受。这里我们就需要用到一个新的东西。叫做波特率、只要波特率相同,就可以进行传输了。
比特率:每秒传输的二进制数,单位是BPS。
TTL----->RS232:由TTL到电脑的串口,就需要MAX3232或者SP3232来达到波特率相同。
串口------->USB接口:CH340或者CP2012来进行波特率转换。
STM32一般用的都是由UASRT的,不过一般使用异步串行通信。
比如USART1_TX和PA9复用 USART1_RX与PA10复用
USART2_TX和PA2复用 USART2_RX与PA3复用
当然这玩意儿看你的芯片手册是咋安排的具体。
首先对于HAL库里的串口函数需要率先认识一些:
第一种是阻塞式发送函数:
HAL_StatusTypeDef HAL_UART_Transmit(UART_HandledTypeDef*huart,//一个外设的地址
Uint8_t*pData,//发送的内容
Uint16_t Size,//发送的字节大小
Uint32_t Timeout);//超时时间
为啥叫阻塞式发送函数呢?就是说发送完,函数才执行完,不然单片机只能执行这个函数,无法干其他事情。所以说虽然逻辑上比较方便,但是应用上其实不太有优势。
接下来看一下非阻塞式的发送函数
HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef*huart,
Uint8_t *pData,
Uint16_t Size);
这个函数是自带发送中断的,首先同样的也需要使能发送中断的,然后数据完成后又进行回调。就可以做些其他事儿了。
一般来说,上述发送完毕之后,就需要用到回调函数
一个是:
void HAL_UART_TxCpltCallback(UART_HandledTypeDef*huart);
void HAL_UART_TxHalfCpltCallback(UART_HandleTypeDef*huart);//这是执行一半就回调的函数。
那么接下来,我们就来举个例子
使用非阻塞式的串口发送函数,将数组的前五个数据发送到USART1,在数据发送完成后,翻转LED的输出电平。
那么程序呢大概如下:
HAL_UART_Transmit_IT(&huart1/*串口一的地址*/),&dat_Txd/*缓冲区的地址*/,5/*5个数据*/);
void HAL_UART_TxCpltCallback(UART_HandleTypeDef*huart)
{
If(huart->instance == USART1)//判断是否是串口一在调用
{
HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_2);
}
}
如果说是阻塞式的函数,就会很简单
HAL_UART_Transmit(&huart1,dat_Txd,5,10000);//最后那个就是超时时间,超时后就会自动结束。
HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_2);
第二种例子就是接受函数:
首先这次就用阻塞式来接受:
HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart,
Uint8_t *pData,
Uint16_t Size,
Uint32_t Timeout);
第二种是非阻塞式的(一般来说都是用非阻塞式的):
HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart,
Uint8_t*pData,
Uint16_t Size);
发送完毕后呢需要调用中断回调函数:
void HAL_UART_RxCpltCallback(UART_HandleTypeDef*huart);
void HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef*huart);
同样的举个例子:
使用非阻塞式的串口接受USART中的一个字节,保存在dat_Rxd变量中,在数据发送完成后,若该字节为0x5A,则翻转LED输出电平。
HAL_UART_Receive_IT(&huart1,&dat_Rxd,1);
Void HAL_UART_RxCpltCallback(UART_HandleTypeDef*huart)
{
If(huart->Instance == USART1){
If(dat_Rxd == 0x5A){
HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_2);
}
}
}
那么接下来就是CubeMX的一个设置
首先对USART1中断使能
接着把波特率改成9600(常用)
然后设置两个LED的OUTPUT大致就可以了,然后生成代码
打开后可以看见代码中多了新的.c文件和一些新的初始化函数。
我们打开usart.c看一下
CubeMX已经把我们需要配置的具体参数,在USART1的初始化函数中配置了。
那么接下来,我们需要完成一下一些比较简单的应用
第一个是向串口1发送“hello world”
其次分别需要发送接收数据。同时提示LED1 OPEN之类的;
用uint8_t来定义一下数组和缓冲区。
然后就开始写阻塞式(非阻塞式)的串口发送函数。
写好之后用串口助手试验一下。
那么这是发送,接下来就需要进行一个接收的功能
首先为了方便,把LED的开关,定义成宏定义的形式,这样会比较的简便,
然后定义一个接收的数据;
接下来同样的,使用Receive函数,然后再启用回调,就是我们上面所提到的步骤。
回调函数乐意直接找到然后自己进行更改;
一定要记住需要再if里面添加再一次的HAL_UART_Receive_IT(&huart1,&Rx__dat,1);
不然只会接受一次!!!
最后进行调试,就非常简单了。