STM32开发 --- USART的3种发送方式

之前写了两三篇关于USART+DMA数据传输的笔记。

这里记录另一种数据发送方式:利用中断发送。


总结三种发种方式, 并分析其优缺点

  1. 正常发送(while);
  2. 使用DMA发送;
  3. 使用中断发送;

实验使用搭建

 

  • 软件: Keil_v5.27  (目前最好用的版本)
  • 硬件: STM32F103C8T6  (魔女开发板  集成下载器, 接线轻松)
  • 串口上位机: 秉火串口调试助手  (野火的, 感觉比原子哥的启动要快)

需要完成代码的兄弟, 到Q群文件夹里下载: 262901124


方式一:正常发送

初学STM32时,必用的发送方式。

看看熟悉的代码:

// 发送一个字符串
void Usart1_SendString( char* buff )
{
    while( *buff !=0 )                      // 检查是否是字符串结束符
    {
        while( (USART1->SR & 1<<7) == 0 );  // 等待发送缓冲区空闲
        USART1->DR = *buff;                 // 填入发送数据
        buff++;                             // 发送数据指针后移
    }
}

优点:代码和逻辑都简单,容易理解!新手必备!

缺点:利用while不断检测发送状态+等待,挨个字节发出,其实很费时;如115200波特率,发送100个字节,至少用时8700us!!而且发送期间,中断响应外,整个程序、系统不能干其它事,如假死一般;


方式二:使用DMA发送

先看代码:

// 发送一个字符串
void Usart1_Send_DMA(char* charTemp) 
{
    u32 num = 0;                                // 发送的数量,注意发送的单位不是必须8位的    
    static u8 Flag_DmaTxInit=0;                 // 用于标记是否已配置DMA发送
    char* t=charTemp ;                          // 用于配合计算发送的数量
    
    while(*t++ !=0)  num++;                     // 计算要发送的数目,这步比较耗时,测试发现每多6个字节,增加1us,单位:8位           
    while(DMA1_Channel4->CNDTR > 0);           // 如果DMA还在进行上次发送,就等待; 得进完成中断清标志,F4不用这么麻烦,发送完后EN自动清零
         
    if( Flag_DmaTxInit == 0)                    // 是否已进行过USAART_TX的DMA传输配置
    {   
        Flag_DmaTxInit  = 1;                    // 设置标记,下次调用本函数就不再进行配置了
        USART1 ->CR3   |= 1<<7;                 // 使能DMA发送
        RCC->AHBENR    |= 1<<0;	                // 开启DMA1时钟  [0]DMA1   [1]DMA2        
 
        DMA1_Channel4->CCR   = 0;               // 失能, 清0整个寄存器, DMA必须失能才能配置
        DMA1_Channel4->CNDTR = num;    	        // 传输数据量   
        DMA1_Channel4->CMAR  = (u32)charTemp;   // 存储器地址 
        DMA1_Channel4->CPAR  = (u32)&USARTx->DR;// 外设地址      

        DMA1_Channel4->CCR |= 1<<4;  		    // 数据传输方向   0:从外设读   1:从存储器读
        DMA1_Channel4->CCR |= 0<<5;  		    // 循环模式       0:不循环     1:循环
        DMA1_Channel4->CCR |= 0<<6; 		    // 外设地址非增量模式
        DMA1_Channel4->CCR |= 1<<7; 	 	    // 存储器增量模式
        DMA1_Channel4->CCR |= 0<<8; 	 	    // 外设数据宽度为8位
        DMA1_Channel4->CCR |= 0<<10; 		    // 存储器数据宽度8位
        DMA1_Channel4->CCR |= 0<<12; 		    // 中等优先级
        DMA1_Channel4->CCR |= 0<<14; 		    // 非存储器到存储器模式	
    }    
    DMA1_Channel4->CCR  &= ~((u32)(1<<0));      // 失能,DMA必须失能才能配置
    DMA1_Channel4->CNDTR = num;                 // 传输数据量
    DMA1_Channel4->CMAR  = (u32)charTemp;       // 存储器地址      
    DMA1_Channel4->CCR  |= 1<<0;                // 开启DMA传输       
} 

代码是寄存器编程,精简。但如果使用标准库,或者HAL库,那么代码量会怕吓怕很多人......

优点:

  1. 占用资源最少,发送100字节(用"处理"这个词更好理解), 只需大约30us, 比方式1发送快290倍!! 
  2. 发送工作都在后台,调试时特省工夫。别看代码好像很复杂,其实过程会很简单,只要配置好DMA基本就没啥事了。

缺点:

  1. 代码长,易出错。  这里指的是使用标准库,或HAL库编写的代码,  调试时, 发量直线下降
  2. 发送处理的时间确实很短, 但后台中还得按设定的波特率进行发送, 115200, 100字节, 后台工作时长还是要8600us左右, 如果在这8600us期间, 又有新的数据要发送出去, 要么等待上次的发送完成,要么停止上次未完的发送。

方式三:发送中断

这种方式,可以说是UART数据发送的最优解!!

先看代码:

static u8 TxBuffer[512] ;                  // 数组大小根据实际数据、发送频率调整
static u8 TxCounter = 0 ;
static u8 LastCount = 0 ;

// 发送一个字符串
void Usart1_SendIE(u8* buf, u8 cnt)         // 指定数据长度,可发送各种数据, 而不仅限于字符串
{
    for(u8 i=0; i<cnt; i++)                 // 把要发送的数据,复制到待发送区(数组)
        TxBuffer[LastCount++] = buf[i];     // 如果加个while, 也可以发送不定长字符串
    
    if( (USARTx->CR1 & 1<<7) == 0 )         // 开启 发送缓冲区空置中断, 在USART初始化时,先不要打开空置中断
        USARTx->CR1 |= 1<<7;     
}

// 中断服务函数
void USART_IRQHANDLER(void)           
{        
    if(USART1->SR & 1<<7)                   // 检查中断来源:发送缓冲区空置——TXE
    {
        USART1->DR = TxBuffer[TxCounter++]; // 发送缓冲区填充一个字节
        
        if(TxCounter == LastCount )         // 检查发送是否完成
            USART1->CR1 &= ~(1<<7);         // 关闭发送缓冲区空置中断
    }   
}  

代码量比想象中的要少,而且很有意思~~~。

优点:

  1. 占用资源少,没准确测量时间,如100字节,估计总用时100us左右吧,但分100次中断分摊。
  2. 发送期间,如果有新的数据要发送,交追加到发送区的尾部,不会像DMA那样被抹掉

缺点:

  1. 逻辑比DMA要多两个弯弯, 调试时有点麻烦;

  • 10
    点赞
  • 77
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值