基于HAL库的stm32中串口的数据收发(使用stm32cubemx工具)
一:什么是串口通信
(1)串口通信是一种通信协议,而通信协议就是通信双方在数据的传输过程中需要共同遵守的协议。数据的发送方按照某种把数据调制成可以被传输的信号,接收方就可以使用相同的协议从信号中解析数据(只有双方都掌握同一种语言时,交谈才能成功,不然就是一段没用的信号)
(2)假设两块单片机要进行通信,他们直接的通信至少需要两根线,因为它们是通过高低电平来传输信号的,而两根线才能够形成电势差。
(3)定义高电平为逻辑1,低电平为逻辑0,串口传输一个字节的过程:首先在空闲状态下,没有数据进行传输的时候,传输线上的是高电平,表示的是逻辑1。当发送端需要发送数据时,就会把电平拉低,作为起始信号,这个时候的接收端检测到了电平拉低,就会做好接收数据的准备。起始信号会占用一个位的时间,称为起始位,在此之后就进入数据的传输。发送端将数据的每一位依次发出,发送方式就是让每一位持续一定的时间,接收端就会对传输线上的电平信号进行采样,进而判断发出的是0还是1。当完成数据的传输之后就会进入校验阶段,接下来这一位叫做校验位,可以对数据的传输与否进行校验。最后就是停止位,发送方会将电平拉高,代表传输完成,这就是串口通信的时序。
(4)数据参数的配置。数据的长度(一般可以使用5~8位)。校验方式(奇校验、偶校验、校无验。如果选择的是奇校验那么发送出来的数据位和校验位里面,逻辑1的个数是奇数,如果接收端发现不是奇数的话,那么就说明数据的传输出现了错误。偶校验则就是逻辑1的个数是偶数,也可以不进行校验)。停止位(一般1~2)。波特率(传输速度,单位是bit/s,也就是每秒钟可以传输多少这样的位,常用的波特率是9600和115200,波特率高的话数据的传输就会变快,但很明显数据的乱码会加大出现的概率 ,且发送端与接收端的波特率需要一致,否则无法进行通信)
(5)单片机串口的接线(开始说两根线),一般情况下,把两块单片机的GND相连接,那么另外一个io口就可以进行数据的发送或者接收,用于发送的引脚一般称为tx引脚,接收称为rx引脚,可以再加上一根线实现相反方向的数据的传输(三根线)
二:使用STM32cubemx配置串口
(1)打开stm32cubemx
(2)进行mcu选项
(3)输入单片机型号,这里我选择的是stm32l432KCU3
(4)调试接口的选择
(5)时钟频率的设置
(6)
(7)参数的配置
(8)生成工程代码
三:使用阻塞方式进行串口的发送和接收
(1)阻塞方式发送
1 打开刚刚生成的keil工程文件并进行编译
2 打开stm32cubemx自动生成的串口的hal库.c文件找到阻塞方式的发送函数
3 将函数在main主函数while循环中进行调用进行循环发送,一共需要四个参数。第一个是串口的句柄这里使用的是串口1。第二个是需要发送的数据,该函数发送定义的类型为unsigned char,需要将需要发送的字符串“abcd”其强制转化为unin8_t * 类型,第三个是字符串的大小,第四个是超时时间,并且设置延时每隔500ms发一次
4 编译下载到单片机
这里将数据发送给电脑来验证,所以需要单片机连接usb转ttl模块 tx连接rx rx连接tx GND 接GND
5 打开串口调试助手选择串口号、波特率、校验位、数据位,打开串口可以发现数据发送成功
(2)阻塞方式接收
1 找到hal库的串口接收函数
2 在while循环内调用串口接收(在这之前先定义局部变量储存数据),然后调用串口接收函数,然通过把接收到的数据发送给pc来进行验证
3打开串口调试助手给打开给单片机发送数据,注意要将发送新行打开不然可能会出现乱码
四:使用串口重定向使用C语言的输入输出函数进行数据的发送和接收(也是阻塞方式)
(1)数据的发送
1 包含头文件
2 重写fputc函数
3 使用printf函数发送字符串
4 打开串口串口调试助手验证
(2)数据的接收
1 重写串口重定向函数
2 定义一个局部变量用来存储接收到的数据 然后调用输入函数
3 打开串口调试助手给单片机发送数据进行验证(这里需要勾选发送新行,因为scanf函数是以换行来确认输入的内容)
五 :使用中断的方式来进行串口的接收与发送
(1)串口中断方式发送
1 先在stm32cubemx中打开串口中断,再重写生成工程打开,进入后编译一下
2 在hal库中找到串口中断发送函数 ,串口中断发送需要三个参数,第一个是串口句柄,第二个是要发送的数据,第三个是数据大小
3 在主函数中while循环内调用
4 打开串口调试助手进行验证
(2)串口中断接收
1 先找到hal库中的串口中断接收函数
2 先定义一个全局变量,局部变量可能会在函数结束后被销毁导致中断接收没地方存放数据,然后在main主函数中调用一次,不需要在while中调用一直占用cpu
3 hal库提供了一个回调函数,我们可以单片机在进行中断接收后在回调函数中进行操作
中断接收到数据后,为了验证收到了数据将收到的数据发送给电脑,然后重写启用串口接收,编译下载程序
4 打开串口调试助手给单片机发送数据进行验证(这里不要勾选发送新行不然可能会有乱码)
六 :使用DMA数据打包的方式发送,解决需要指定字符串长度的问题
(1)DMA是单片机中数据搬运的一个助手,它可以在内存与内存之间,或者内存与外设之间,进行数据的搬运,cpu只需要告诉单片机要搬运哪些数据就行了,而不需要控制每个字节的传输,降低了cpu的负载
(2)在stm32cubemx中进行串口的配置
1 找到DMA的选项卡
2 进行配置,重写生成代码
(3)串口DMA发送
1 找到hal库中的dma发送函数,在main函数while循环里调用,和中断一样还是需要四个参数第一个串口句柄,第二个需要发送的数据,第三个数据的大小
2 打开串口调试助手进行验证
(4)串口DMA接收
1 找到hal库的串口DMA接收函数,在刚刚中断接收的地方调用它一次,while循环内无需调用
2 回调函数也修改成DMA
3 编译下载烧录到单片机,打开串口调试助手给单片机发送数据,还是需要发送指定的五个字符结束才能发送成功,还是没解决要指定字符长度的问题
(5)解决指定字符长度的方法
(1)设置空闲中断,开启空闲中断,当单片机发生中断时判断是否是空闲中断,当进入空闲中断时就会知道数据已经全部发送完毕,可以进行处理
1 stm32cubemx确认串口中断是否打开
2 在DMA方式下进行修改
2.1 将定义用来接收数据的存储全局变量大小变为200
2.2 将串口的接收回调函数屏蔽或删除
2.3 开启串口接收函数的调用不去除,接收数据大小改为200
2.4 在hal库串口.h文件中找到定义好的开启串口空闲中断的宏,在主函数中调用
2.5 每次串口发生中断时都会进入这个函数,要对这个函数进行一些配置完成数据的不定长收发
2.6 步骤 1:分支语句判断是否发生空闲中断(调用hal库串口头文件中获取空闲中断标志位的宏来检查是否发生空闲中断)->2:如果确实发生空闲中断先清除空闲中断标志位(也在hal库串口头文件中定义了宏)->在hal库.c文件中找到停止DMA数据接收函数,参数是使用的串口的串口句柄->在DMA进行接收时内部会有一个计数器来计数接收的数据大小,定义变量用来接收调用这个函数(函数返回当前DMA通道传输中剩余的数据单元数)->调用DMA发送函数,参数为使用的串口句柄、要发送的数据(这里就是定义的用来接收数据全局变量,因为是在别的文件调用,所以需要用extern关键字来在中断文件中进行声明才能调用)、发送数据大小为刚刚用来存储DMA实际得到的数据的值->重新开启DMA接收
2.7 打开串口调试助手进行验证(可以看到已经实现串口不定长进行数据的接收)
(2)自己写函数实现不定长的数据发送
1 自定义函数名,不需要返回值 ,需要两个参数 使用的串口的串口句柄,以及要发送的数据(定义一个unsigned char 指针指针指向一个静态局部变量地址)
2 :函数内部实现:调用此函数后检测指针指向的地址(字符串首地址)是否为'0'(字符串结束),是则结束while循环,不是则字符串未发送数据继续进行循环。
3 :while循环内部:调用串口发送函数参数为需要使用的串口的串口句柄、需要发送的字符串的首地址(指针)、一次发一个字节、超时时间,发送一个字节后指针加一指向字符串首地址后的一个字节(while循环进行一次+),直到发送完整个字符串监测到指针指向'0'后退出while循环,结束函数
/********************************************************************* 函数名:uart_send_bits 作用 :串口发送,实现不定长字符串发送 参数 :*huart,*pData 串口句柄,要发送的数据 返回值:无 **********************************************************************/ void uart_send_bits(UART_HandleTypeDef *huart,const uint8_t *pData) { while(*pData != '\0') { HAL_UART_Transmit(&huart1,pData,1,0xffff); pData++; } printf("\r\n"); }