发新帖本帖赏金 10.00元(功能说明)我要提问
123下一页
返回列表
打印
[uCOS/RTOS]

基于FreeRTOS的UART空闲中断框架设计

[复制链接]
19456|41
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 caizhiwei 于 2021-3-9 22:16 编辑

#申请原创#
基于FreeRTOSUART空闲中断框架设计
设计背景:
     针对大部分国产低端MCU(ARM-CortexM0)来说,并没有空闲中断,此时就需要一个定时器Timer配合来完成此任务。对于UART接受不定长数据,空闲中断还是非常实用的!
知识点:FreeRTOS的二值信号量 Timer UART
空闲中断的原理:     IDLE中断叫空闲中断,不叫帧中断。那么什么叫空闲,怎么定义空闲呢?在实际发送数据的时候,比如一串字符串,其实发送的两个字符之间间隔非常短,所以在两个字符之间不叫空闲。空闲的定义是总线上在一个字节的时间内没有再接收到数据,空闲中断是检测到有数据被接收后,总线上在一个字节的时间内没有再接收到数据的时候发生的。而总线在什么情况时,会有一个字节时间内没有接收到数据呢?一般就只有一个数据帧发送完成的情况,所以串口的空闲中断也叫帧中断。
开发环境Win10,  MDK5.28,  HC32L136
设计步骤:
    这里不做长篇大论,列举了重要的核心部分讲解,便于大家移植。附件中带有完整的工程代码。
首先定义一个结构体和信号量。
extern SemaphoreHandle_t AT_RX_Semaphore;

/*用于空闲中断判断*/
typedef struct
{
uint16_t uart_cnt;
uint16_t timer_cnt;
}stcUART_Idle;

extern stcUART_Idle UART_Idle;

2. 串口部分代码:
/**********************************************************************************************
    *函数功能:初始化UART
    *UARTx:  选择初始化UART端口号
    *Parity: 奇偶校验位
    *说明IO用使用复位模式2,DMA默认是使能
**********************************************************************************************
*/
void BSP_UARTx_Init(M0P_UART_TypeDef *UARTx, uint32_t baud, en_uart_mmdorck_t Parity)
{
         if(UARTx == M0P_UART0)
         {                    
                Uart0_init(baud,Parity);
                EnableNvic(UART0_IRQn, IrqLevel3, TRUE);       ///<系统中断使能                  
         }
         if(UARTx == M0P_UART1)
         {                        
                EnableNvic(UART1_IRQn, IrqLevel3, TRUE);           ///<系统中断使能        
         }        
}   


//串口0模块配置
static void Uart0_init(uint32_t baud, en_uart_mmdorck_t Parity)
{   
        stc_gpio_cfg_t stcGpioCfg;
    stc_uart_cfg_t  stcCfg;
    stc_uart_baud_t stcBaud;
        
    DDL_ZERO_STRUCT(stcGpioCfg);
    DDL_ZERO_STRUCT(stcCfg);
    DDL_ZERO_STRUCT(stcBaud);
        
    Sysctrl_SetPeripheralGate(SysctrlPeripheralGpio,TRUE); //GPIO外设模块时钟使能
   
    stcGpioCfg.enDir = GpioDirOut;
    Gpio_Init(GpioPortA,GpioPin9,&stcGpioCfg);
    Gpio_SetAfMode(GpioPortA,GpioPin9,GpioAf1); //配置PA09 为UART0 TX
    stcGpioCfg.enDir = GpioDirIn;
    Gpio_Init(GpioPortA,GpioPin10,&stcGpioCfg);
    Gpio_SetAfMode(GpioPortA,GpioPin10,GpioAf1);//配置PA10 为UART0 RX

    Sysctrl_SetPeripheralGate(SysctrlPeripheralUart0,TRUE);//UART0外设模块时钟使能
        
        stcCfg.enRunMode = UartMskMode3;     //模式3
    if(Parity == UartMskEven)
        {
                stcCfg.enMmdorCk = UartMskEven;      //偶校验
        }
        else if(Parity == UartMskOdd)
        {
                stcCfg.enMmdorCk = UartMskOdd;       //奇校验
        }
        else
        {
                stcCfg.enRunMode = UartMskMode1;     //模式1,奇偶检验无效
        }
    stcCfg.enStopBit = UartMsk1bit;      //1位停止位
    stcCfg.stcBaud.u32Baud = baud;       //波特率9600
    stcCfg.stcBaud.enClkDiv = UartMsk8Or16Div;         //通道采样分频配置
    stcCfg.stcBaud.u32Pclk = Sysctrl_GetPClkFreq();    //获得外设时钟(PCLK)频率值
    Uart_Init(M0P_UART0, &stcCfg);       //串口初始化

    Uart_ClrStatus(M0P_UART0,UartRC);    //清接收请求
    Uart_ClrStatus(M0P_UART0,UartTC);    //清发送请求
    Uart_EnableIrq(M0P_UART0,UartRxIrq); //使能串口接收中断
    //Uart_EnableIrq(M0P_UART0,UartTxIrq); //使能串口发送中断                     
        //使能DMA发送, DMA相关通道使能后,如果Tx Buff为空,会立马启动传输
        Uart_EnableFunc(M0P_UART0,UartDmaTxFunc);  
}
3. 编写UART中断函数


在这里采用了循环数组接收,没有使用队列,可以省点资源,效果差不多,数组处理更方便。

3. Timer定时器,这里选用2ms周期中断,并通过UART中断中启动,在Timer中断中关闭。
#include "bsp_timer.h"

#include "bsp_uart.h"


SemaphoreHandle_t BinSem_UART_Idle;


//Timer3 配置,用于uart0 的空闲中断
void BSP_Timer3_init(uint16_t u16Period)
{
    uint16_t                    u16ArrValue;
    uint16_t                    u16CntValue;
    stc_tim3_mode0_cfg_t     stcTim3BaseCfg;   
    //结构体初始化清零
    DDL_ZERO_STRUCT(stcTim3BaseCfg);
   
    Sysctrl_SetPeripheralGate(SysctrlPeripheralTim3, TRUE); //Base Timer外设时钟使能
   
    stcTim3BaseCfg.enWorkMode = Tim3WorkMode0;              //定时器模式
    stcTim3BaseCfg.enCT       = Tim3Timer;                  //定时器功能,计数时钟为内部PCLK
    stcTim3BaseCfg.enPRS      = Tim3PCLKDiv32;              //PCLK/32
    stcTim3BaseCfg.enCntMode  = Tim316bitArrMode;           //自动重载16位计数器/定时器
    stcTim3BaseCfg.bEnTog     = FALSE;
    stcTim3BaseCfg.bEnGate    = FALSE;
    stcTim3BaseCfg.enGateP    = Tim3GatePositive;
   
    Tim3_Mode0_Init(&stcTim3BaseCfg);                       //TIM3 的模式0功能初始化        
    u16ArrValue = 0x10000 - u16Period ;
    Tim3_M0_ARRSet(u16ArrValue);                            //设置重载值(ARR = 0x10000 - 周期)  
    u16CntValue = 0x10000 - u16Period;   
    Tim3_M0_Cnt16Set(u16CntValue);                          //设置计数初值   
    Tim3_ClearIntFlag(Tim3UevIrq);                          //清中断标志        
    Tim3_Mode0_EnableIrq();                                 //使能TIM3中断(模式0时只有一个中断)        
    EnableNvic(TIM3_IRQn, IrqLevel3, TRUE);                 //TIM3 开中断
        //Tim3_M0_Run();   //TIM3 运行
}

/*去初始化,进低功耗功耗前调用此接口*/
void BSP_Timer3_Deinit(void)
{
        stc_tim3_mode0_cfg_t     stcTim3BaseCfg;   
    DDL_ZERO_STRUCT(stcTim3BaseCfg);                         //结构体初始化清零
        Tim3_Mode0_Init(&stcTim3BaseCfg);   
        Tim3_ClearIntFlag(Tim3UevIrq);                //清中断标志        
    Tim3_Mode0_DisableIrq();
        Tim3_M0_Stop();
}


UART和Timer如何配合使用,上面的函数已经给出了。
最后,中断中已经给出了信号量,后续如何处理呢?
用一个任务去接收信号就好了:


实验效果:

源码整理后的附件:
游客,如果您要查看本帖隐藏内容请回复


使用特权

评论回复

打赏榜单

21小跑堂 打赏了 10.00 元 2021-03-10
理由:恭喜通过原创文章审核!请多多加油哦!

相关帖子

沙发
caizhiwei|  楼主 | 2021-3-9 22:12 | 只看该作者
@21小跑堂
申请原创,哈哈

使用特权

评论回复
板凳
zhdm| | 2021-3-9 22:27 | 只看该作者
谢谢分享

使用特权

评论回复
地板
〽️〽️〽️| | 2021-3-12 09:05 | 只看该作者
谢谢!

使用特权

评论回复
5
ccd007| | 2021-3-12 09:07 | 只看该作者
挺实用的一个帖子

使用特权

评论回复
6
gyh974| | 2021-3-12 10:53 | 只看该作者
没有IDLE空闲中断的MCU有福了

使用特权

评论回复
7
wifi99| | 2021-3-13 16:03 | 只看该作者
来学习学习

使用特权

评论回复
8
Thomas717| | 2021-3-13 20:09 | 只看该作者
谢谢楼主

使用特权

评论回复
9
goodfriends2004| | 2021-3-14 07:42 | 只看该作者
谢谢楼主!

使用特权

评论回复
10
lawesly| | 2021-3-14 11:09 | 只看该作者
这个方法不错, 学习下

使用特权

评论回复
11
lfc315| | 2021-3-14 15:58 | 只看该作者
不错。。。。。。。。。。。

使用特权

评论回复
12
keke| | 2021-3-15 10:36 | 只看该作者
来,学习学习

使用特权

评论回复
13
starsfu| | 2021-3-15 16:10 | 只看该作者
学习使用

使用特权

评论回复
14
brosoon| | 2021-3-16 17:56 | 只看该作者
let me see !

使用特权

评论回复
15
sleaven| | 2021-3-17 09:30 | 只看该作者
看看 学习学习

使用特权

评论回复
16
qj984229477| | 2021-3-17 14:21 | 只看该作者
11111111111111111111111

使用特权

评论回复
17
bbschen| | 2021-3-17 14:48 | 只看该作者
路过,看看

使用特权

评论回复
18
kk的回忆| | 2021-3-21 17:53 | 只看该作者
挺好的例子,学习一下

使用特权

评论回复
19
lcfmax| | 2021-3-23 12:02 | 只看该作者

挺好的例子,学习一下

使用特权

评论回复
20
maryshy| | 2021-3-23 16:04 | 只看该作者
看起来挺有用的

使用特权

评论回复
发新帖 本帖赏金 10.00元(功能说明)我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

100

主题

857

帖子

14

粉丝