基于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");
			
}

                

        

  • 22
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
你可以使用STM32F103的硬件UART模块来实现串口收发任意长度的数据包,而不使用HAL库。下面是一个示例代码,展示了如何使用STM32Cube库来配置和控制UART模块。 首先,你需要在STM32CubeMX配置UART模块的引脚和时钟设置。确保使能相应的UART模块,并设置合适的波特率和数据位数。 接下来,在生成的代码,找到usart.c文件,并添加以下函数: ```c void UART_SendData(uint8_t* data, uint16_t len) { for (uint16_t i = 0; i < len; i++) { while (!(USART1->SR & USART_SR_TXE)); // 等待发送完成 USART1->DR = data[i]; // 发送数据 } while (!(USART1->SR & USART_SR_TC)); // 等待发送完毕 } void UART_ReceiveData(uint8_t* data, uint16_t len) { for (uint16_t i = 0; i < len; i++) { while (!(USART1->SR & USART_SR_RXNE)); // 等待接收到数据 data[i] = USART1->DR; // 读取接收到的数据 } } ``` 以上代码,UART_SendData函数用于发送数据包,UART_ReceiveData函数用于接收数据包。你可以根据需要修改USART1为你要使用的UART模块。 最后,在主函数调用这两个函数来发送和接收数据包。例如: ```c #define PACKET_SIZE 10 int main(void) { uint8_t txData[PACKET_SIZE] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A}; uint8_t rxData[PACKET_SIZE] = {0}; // 初始化串口 // 发送数据包 UART_SendData(txData, PACKET_SIZE); // 接收数据包 UART_ReceiveData(rxData, PACKET_SIZE); // 处理接收到的数据 while (1) { // 主循环 } } ``` 这样,你就可以在STM32F103上实现串口收发任意长度的数据包,而不使用HAL库。记得根据你的具体硬件和需求进行适当的修改。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值