【分享】利用队列 + 发送完成中断来进行串口发送,避免while一直等待

2019-12-20 21:39发布

在用printf时,很多人都用的如下语句来重定义fputc
//        while((USART1->SR & 0X80)==0);//等待发送寄存器空   1000 0000=== B7位
//        USART1->DR = (u8) ch;

这个语句,问题显而易见,就是太占用CPU时序了,下面程序尝试使用存入队列,然后在发送完成中断中按顺序字符输出(第一个字符是直接放入DR的):
已经上机实测了2周了都没有任何问题,分享给大家,欢迎批评指正,觉得好的话顶下哦~

头文件,变量:
#include <stm32f10x_lib.h>                 
#include "sysinit.h"

#define TXBUFLIM 390
#define TXBUFCAP 400

extern u8         txbuf[];                //400 时 0-399
extern u32         txpoint;                //指向正在准备发送的位置                值范围0到CAP-1
extern u32         txtail;                //指向最后一个被存入队列的位置
extern u32         arynum;                //记录队列中准备发送的数量


//putc函数中只管往队列写值

#include "stdio.h"

u8 txbuf[TXBUFCAP];        //400 时 0-399
u32 txpoint=0;                //指向下一个发送数据在队列的位置                值范围0到CAP-1
u32 txtail =0;                //指向下一个数据该,存入队列的位置
u32 arynum =0;                //记录队列中准备发送的数量

//重定义fputc函数 放入队列                                                         //发送程序在:void USART1_IRQHandler(void)
int fputc(int ch, FILE *f)
{          static s32 firstone=0;                        //第一个值时=1
        while( arynum >= TXBUFLIM );        //满时,等待

        if((arynum==0)        &&        (firstone==0))        {                                                                                 //第一个数,直接出
                  USART1->DR = (u8) ch;
                  firstone=1;
                                }
        else{       
                        txbuf[txtail] = (u8)ch;
                        txtail++;        if(txtail >= TXBUFCAP)txtail=0;
                        arynum++;
                        firstone=0;
                }
       
//        while((USART1->SR & 0X80)==0);//等待发送寄存器空   1000 0000=== B7位
//        USART1->DR = (u8) ch;

        return ch;
}

//////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////
//加入以下代码,include stdio,自定义fputc,即可支持printf函数,而不需要选择use MicroLIB          
#pragma import(__use_no_semihosting)            
//标准库需要的支持函数                 
struct __FILE
{
        int handle;
        /* Whatever you require here. If the only file you are using is */
        /* standard output using printf() for debugging, no file handling */
        /* is required. */
};
/* FILE is typedef’ d in stdio.h. */
FILE __stdout;      
//定义_sys_exit()以避免使用半主机模式   
_sys_exit(int x)
{
        x = x;
}


中断函数中,按顺序发送:
void USART1_IRQHandler(void)
{         u8 Res;

        if(USART1->SR&(1<<5))//接收到数据
        {         
                Res=USART1->DR;                                                                               
                                                                                                                                                                ////发回去
                                                                                                                                                                //        while((USART1->SR & 0X80)==0);
                                                                                                                                                                //        USART1->DR = Res;
                Res=Res;
        }
       
        if(USART1->SR&(1<<6))//发送完成
        {        USART1->SR&=~(1<<6);        //置零
                                                                                                                                 //USART_ClearITPendingBit(USART1,USART_IT_TC);           //IT FLAG 函数内部相同的都是清除SR
                                                                                                                                //USART_ClearFlag(USART1,USART_FLAG_TC);
                if(arynum!=0){       
                        USART1->DR = txbuf[txpoint];

                        txpoint++;        if(txpoint >= TXBUFCAP)txpoint=0;
                        arynum--;
                        //检查用,安全保障
                        if(arynum==0)txtail=txpoint;
                                                }

        }
                       
}


//初始化配置:
void USART_Configuration(void)
{
    USART_InitTypeDef USART_InitStructure;
//U1:57600串口接电脑,printf                                     /*9600;//57600;//19200;115200;//*/
    USART_InitStructure.USART_BaudRate = 57600;//test~9600;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_Parity = USART_Parity_No;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
    USART_Init(USART1, &USART_InitStructure);
   
    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);                  //接收中断
    USART_ITConfig(USART1, USART_IT_TC, ENABLE);                  //发送完成中断

    USART_Cmd(USART1, ENABLE);

//串口1中断          调试
    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQChannel;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;           //NVIC响应 1 1级
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
36条回答
Flynn1986
1楼-- · 2019-12-24 05:19
方法是好办法,不过printf作为调试打印时还是等待的好,这样可以实时查看打印的数据。
Syth
2楼-- · 2019-12-24 05:19
MARK   
twd3621576
3楼-- · 2019-12-24 09:37
mark! 记录
djkc
4楼-- · 2019-12-24 13:46
 精彩回答 2  元偷偷看……
ronic
5楼-- · 2019-12-24 13:46
我顶,很有用
su33691
6楼-- · 2019-12-24 16:05
现在有很多单片机内置串口硬件FIFO,使用起来更方便。

一周热门 更多>