单片机串口数据处理(1)——串口中断发送数据

本文对比了两种STM32串口发送数据的方法:死等方式和中断方式。死等方式在while循环中等待字发送完成,影响系统实时性;中断方式通过使能发送缓冲区空中断,实现数据分片发送,有效提高系统实时性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

实时性在嵌入式开发中的非常重要,优化MCU串口传输处理方式可以提高嵌入式系统的实时性。在互联网上学习并亲自实验(基于STM32单片机)后,我将分两次介绍优化MCU串口收发数据的方法,参考资料将在第二篇博客中列出。第一次先介绍串口发送数据的优化。

发送方式一:

方式一采用“死等”的方式发送数据,即在while循环中等待字发送完成标志位置位。

void usartsend(void)
{
    while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET); //等待上一字节发送完成 
    USART1->DR=txbuf[cnt]; //要发送的字节存入串口数据寄存器 
}

void sendcmd(void)
{
    for(cnt=0;cnt<100;cnt++)//发送100个字节
    {
        usartsend();//调用字节发送函数
    }
}

这种方式在while循环中消耗了大量时间,而且sendcmd函数中一遍遍地调用usartsend函数也比较费时。实验中我采用的波特率为115200,理论上发送完100字节数据耗时约8.68ms,而在硬件仿真时的耗时约9.45ms。在这9.54ms内,MCU除了发送字节和while等待外没有处理其他任务,严重影响系统实时性。

发送方式二:

方式二采用中断的方式发送数据。要发送数据时,使能串口的发送缓冲区空中断,在ISR中判断是否有数据要发送,如果有,则将要发送的字节存入串口数据寄存器。当所有数据发送完毕后禁止串口的发送缓冲区空中断。

void usartsend(void)
{
    USART_ITConfig(USART1,USART_IT_TXE,ENABLE);//使能串口的发送缓冲区空中断
}

void USART1_IRQHandler(void) //串口1的ISR              
{
    if(USART_GetITStatus(USART1,USART_IT_TXE)==SET)
    {
        USART1->DR=txbuf[cnt];
        cnt++;
        if(cnt>=100)
        {
            USART_ITConfig(USART1, USART_IT_TXE, DISABLE);//数据发送完毕,禁止串口的发送缓冲区空中断
        }
    }
} 

这种方式主要是ISR占用时间。采用115200的波特率实验时,发送100字节数据用时约8.51ms。用时小于理论时间(8.68ms)的原因可能是最后一个字节没发送完程序就到了我设的断点。

第二种方法的用时比第一种方法少。更值得注意的是第二种方法花费的8.51ms是分片的,程序不会死等8.51ms,在此期间MCU可以处理其他任务,系统的实时性高。而第一种方法程序死等9.54ms,MCU在此期间无法处理其他任务,实时性收到严重影响。

### 51单片机串口通信实现英文字符和数据发送 #### 单片机串口初始化 为了使能51单片机串口功能,需先完成串口中断配置以及波特率设置。通常情况下,串口工作模式被设定为方式1(8位异步通信),并利用定时器T1作为波特率发生器[^1]。 以下是典型的串口初始化函数代码示例: ```c void uart_init() { TMOD |= 0x20; // 设置T1为模式2自动重装载 TH1 = 0xFD; // 波特率为9600bps, fosc=11.0592MHz SCON = 0x50; // 串口工作于方式1,允许接收 TR1 = 1; // 启动T1计数器 } ``` 上述代码中`TH1`寄存器用于定义波特率分频值,而`SCON`控制寄存器则设定了串口的工作模式及其基本属性。 #### 字符与字符串发送 对于简单的英文字母或ASCII码范围内的数值传输,可以调用专门设计好的子程序来逐字节处理待发的数据流。下面分别展示单独字符及整条消息传送的方法[^2]: - **单一字符发送** ```c void uart1_sendByte(unsigned char byte){ while(!TI); // 等待上一次发送结束 TI = 0; SBUF = byte; // 将要发送的数据放入SBUF缓冲区 } ``` 此部分逻辑等待直到前一帧完全送出后再加载新的目标值到移位寄存器里去。 - **字符串发送** 当需要连续传递多段信息时,则可循环调用前述基础单元操作构成更高级别的封装形式如下所示: ```c void uart1_sendstring(unsigned char *str){ unsigned int i=0; while (*(str+i) != '\0') { // 判断当前指针位置是否到达终止标志'\0' uart1_sendByte(*(str+i)); // 调用单字节发送函数 delay_ms(1); // 延迟一定时间防止冲突 i++; } } ``` 这里引入了一个额外延时环节以确保每轮交互之间留有足够的间隔避免潜在干扰现象的发生。 #### 数值转换成字符串再发送 如果打算把某些变量比如温度传感器读取结果之类的量化指标也纳入输出序列当中的话,那么就需要先把它们转化为对应的文本表达形式然后再按照前面介绍过的流程执行下去。例如针对无符号八比特整形参数的情况我们可以这样写: ```c void uart1_sendnum(unsigned char num1){ char buffer[4]; itoa(num1,buffer,10); uart1_sendstring(buffer); } ``` 其中运用到了标准库里的itoa函数负责完成从数字至相应进制编码下的字符串映射过程。 综上所述,借助以上几个核心组件即可轻松达成基于51系列MCU平台之上与其他设备间的基础级资料交换需求了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值