打印

华大hc32f460 timer0怎么配置可以使用串口超时中断

[复制链接]
9113|22
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
jinyiheng|  楼主 | 2022-10-6 00:14 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
使用串口超时中断时,对应的timer0计数时钟怎么选择??

使用特权

评论回复
沙发
jinyiheng|  楼主 | 2022-10-6 00:18 | 只看该作者
file:///C:/Users/jyc/Desktop/j1.png

使用特权

评论回复
板凳
jinyiheng|  楼主 | 2022-10-6 00:19 | 只看该作者
file:///C:/Users/jyc/Desktop/j2.png

使用特权

评论回复
地板
毛大人跟班| | 2022-10-8 10:14 | 只看该作者
华大代理,提供技术支持。 877378012(QQ/VX)

使用特权

评论回复
5
wubangmi| | 2022-10-8 14:18 | 只看该作者
有现成的例程可以参考,请去小华半导体官网下载例程

使用特权

评论回复
6
cyclefly| | 2022-10-11 21:18 | 只看该作者
现成的例程吧

使用特权

评论回复
7
martinhu| | 2022-10-12 15:35 | 只看该作者
有例程,上小华官网下载ddl驱动库

使用特权

评论回复
8
tpgf| | 2022-11-1 11:45 | 只看该作者
通过判断接收连续2个字符之间的时间差不大于10ms来决定是不是一次连续的数据.

使用特权

评论回复
9
qcliu| | 2022-11-1 12:16 | 只看该作者
我感觉这个超时的时间应该是根据自己的设备来设定的一个期望值或者是经验值

使用特权

评论回复
10
drer| | 2022-11-1 13:15 | 只看该作者
选择哪种计数时钟取决于需要确定超市多长时间

使用特权

评论回复
11
coshi| | 2022-11-1 13:49 | 只看该作者
//main.c
/****************************************************
程序功能:串口中断+定时中断实现超时接收串口数据
          上位机发送一串数据,单片机串口接收并返回接收的数据
          配置串口,遵循“9600,N,8,1”
          波特率:9600bps @11.0592MHz
          无校验位:N
          数据位:8
          停止位:1
****************************************************/

#include <reg51.h>
#include "delay.h"
#include "uart.h"

void Timer0Init(void);

void main()
{
        Timer0Init();//定时器初始化
        UartInit();//串口初始化
        EA = 1;//开总中断
  //提示信息
        printf("Wait for Serial Communication Test Start.\r\n");
        printf("Please Send a string of data:\r\n");
        DelayXms(100);
        while(1)
        {
                if(recv_flag)//如果接收到数据
                {
                        recv_flag = 0;//清零接收标志位
                        start_timer = 0;//关软件定时器
                        sendString(recv_buf);//处理数据
                        clr_recvbuffer(recv_buf);//清除缓冲buffer
                }
        }
}
void Timer0Init(void)                //1毫秒@11.0592MHz
{
        TMOD &= 0xF0;                //设置定时器模式
        TMOD |= 0x01;                //设置定时器模式
        TL0 = 0x66;                //设置定时初值
        TH0 = 0xFC;                //设置定时初值
        TF0 = 0;                //清除TF0标志
        ET0 = 1;//开定时器0中断
        TR0 = 1;                //定时器0开始计时
}
//定时器中断服务函数
void timer0_ISR() interrupt 1
{
        TR0 = 0;
        if(start_timer == 1)//如果软件定时器标志位置1
        {
                recv_timer_cnt++;//1、累加定时时间计数器
                if(recv_timer_cnt > MAX_REV_TIME)//2、判断定时时间是否超过了设定的最大的阈值,
                                                       //超过则说明等待一段时间后没有新的数据到,我们
                                                 //判断一包数据接收完毕
                {
                        recv_timer_cnt = 0;//3、清除定时计数器 处理数据 清除buffer(放到数据处理之后)
                        recv_cnt = 0;
                        recv_flag = 1;//置接收完成标志       
                }
        }
        TL0 = 0x66;                //设置定时初值
        TH0 = 0xFC;                //设置定时初值
        TR0 = 1;//打开定时器
}

使用特权

评论回复
12
kxsi| | 2022-11-1 14:14 | 只看该作者
看一下这部分代码
/* 串口参数配置 */
int hal_uart_conf_init (uint32_t baude)
{
    PWC_Fcg1PeriphClockCmd(PWC_FCG1_PERIPH_USART2, Enable);  /* 使能串口时钟 */

    stc_irq_regi_conf_t stcIrqRegiCfg;

    const stc_usart_uart_init_t stcInitCfg = {               /* 配置串口参数 */
        UsartIntClkCkNoOutput,
        UsartClkDiv_16,
        UsartDataBits8,
        UsartDataLsbFirst,
        UsartOneStopBit,
        UsartParityNone,
        UsartSampleBit8,
        UsartStartBitFallEdge,
        UsartRtsEnable,
    };

    if (USART_UART_Init (M4_USART2, &stcInitCfg) != Ok)
    {
        while (1)
        {
        }
    }

    /* Set baudrate */
    if (Ok != USART_SetBaudrate (M4_USART2, baude)) /* 配置波特率 */
    {
        while (1)
        {
        }
    }
    else
    {
    }

    /* 串口接收错误中断配置 */
    stcIrqRegiCfg.enIRQn      = Int000_IRQn;     /* 中断号,可通过参考手册查阅对应的中断号 */
    stcIrqRegiCfg.pfnCallback = &uart2_err_cb;   /* 中断回调函数 */
    stcIrqRegiCfg.enIntSrc    = INT_USART2_EI;   /* 错误中断向量号,可通过参考手册查阅对应的中断号*/
    enIrqRegistration (&stcIrqRegiCfg);
    NVIC_SetPriority (stcIrqRegiCfg.enIRQn, DDL_IRQ_PRIORITY_00); /* 配置中断优先级 */
    NVIC_ClearPendingIRQ (stcIrqRegiCfg.enIRQn);
    NVIC_EnableIRQ (stcIrqRegiCfg.enIRQn);

    /* 串口接收超时中断配置 */
    stcIrqRegiCfg.enIRQn      = Int001_IRQn;           /* 中断号,可通过参考手册查阅对应的中断号 */
    stcIrqRegiCfg.pfnCallback = uart1_rx_timeout_cb;   /* 串口超时中断回调函数 */
    stcIrqRegiCfg.enIntSrc    = INT_USART2_RTO;        /* 串口2超时中断向量号,可通过参考手册查阅对应的中断号 */
    enIrqRegistration (&stcIrqRegiCfg);
    NVIC_SetPriority (stcIrqRegiCfg.enIRQn, DDL_IRQ_PRIORITY_00);
    NVIC_ClearPendingIRQ (stcIrqRegiCfg.enIRQn);
    NVIC_EnableIRQ (stcIrqRegiCfg.enIRQn);

    /*使能串口接收、发送、中断等 function*/
    USART_FuncCmd (M4_USART2, UsartRx, Enable);          /* 使能串口接收 */
    USART_FuncCmd (M4_USART2, UsartRxInt, Enable);       /* 使能串口接收中断,这里主要处理串口故障中断清标志位 */
    USART_FuncCmd (M4_USART2, UsartTimeOut, Enable);     /* 使能串口超时功能 */
    USART_FuncCmd (M4_USART2, UsartTimeOutInt, Enable);  /* 使能串口超时中断功能 */
    USART_FuncCmd (M4_USART2, UsartTx, Enable);          /* 使能串口发送 */

    return 0;
}

/* 串口超时中断回调函数 */
static void uart2_err_cb (void)
{
    /* 清除错误标志位 */
    USART_ClearStatus(M4_USART2, UsartParityErr);
    USART_ClearStatus(M4_USART2, UsartFrameErr);
    USART_ClearStatus(M4_USART2, UsartOverrunErr);
    USART_ClearStatus(M4_USART2, UsartParityErr);
    USART_ClearStatus(M4_USART2, UsartRxNoEmpty);
    USART_ClearStatus(M4_USART2, UsartTxComplete);
    USART_ClearStatus(M4_USART2, UsartTxEmpty);
    USART_ClearStatus(M4_USART2, UsartRxTimeOut);
    USART_ClearStatus(M4_USART2, UsartRxMpb);
}

/* 串口超时中断回调函数 */
static void uart1_rx_timeout_cb (void)
{
    /* 清除标记位 */
    TIMER0_Cmd (M4_TMR01, Tim0_ChannelB, Disable);
    TIMER0_ClearFlag (TIMER_ID, Tim0_ChannelB);
    USART_ClearStatus (M4_USART2, UsartRxTimeOut);

    uart_parm.rx_cnt = uart_parm.rx_len - M4_DMA1->MONDTCTL0_f.CNT;

    if (uart_parm.rx_cnt > 0)
    {
        /* 这里可以添加串口接收标志位置位或者发送事件去处理串口接收到的数据 */
        extern void uart_evt_r_send (void);
        uart_evt_r_send ();  /* 这里我使用的是rt-thread,所以发送接收事件给串口处理线程 */

        /* 串口接收使能 */
        uart_dma_rx_start (uart_parm.rx_buf, uart_parm.rx_len); /* uart_parm.rx_len=接收buf的大小 */
    }
}

/* 定时器配置(串口超时是基于定时器的,串口和定时器的对应关系可以通过参考手册查阅,我是用uart2对应的就是timer01的b通道) */
static void timer0b_init (void)
{
    stc_clk_freq_t stcClkTmp;
    stc_tim0_base_init_t stcTimerCfg;
    stc_tim0_trigger_init_t StcTimer0TrigInit;

    MEM_ZERO_STRUCT (stcClkTmp);
    MEM_ZERO_STRUCT (stcTimerCfg);
    MEM_ZERO_STRUCT (StcTimer0TrigInit);

    /* 定时器时钟使能 */
    PWC_Fcg2PeriphClockCmd (PWC_FCG2_PERIPH_TIM01, Enable);

    /* 计数器清零 */
    TIMER0_WriteCntReg (M4_TMR01, Tim0_ChannelB, 0u);

    /* 配置B通道 */
    /* 这里是我的参数,仅供参考。各位可以根据自己的参数实际计算得到一个可靠的参数配置
       PLCK1=100M  32分频=3125K  计数500=160us 1000=320us  波特率=57600 一个bit大概=17us  */

    /* 同步时钟=LRC或者XTAL32   异步时钟=PCLK1或者内部硬件触发事件 */
    stcTimerCfg.Tim0_CounterMode      = Tim0_Sync; // Tim0_Async;

    /* 如果选异步时钟,就在这里选择LRC或者XTAL32 */
    // stcTimerCfg.Tim0_AsyncClockSource = Tim0_LRC;  

    /* 如果选同步时钟,就在这里选择PCLK1或者内部硬件触发事件 */           
    stcTimerCfg.Tim0_SyncClockSource  = Tim0_Pclk1;   

    /* 分频系数 */           
    stcTimerCfg.Tim0_ClockDivision    = Tim0_ClkDiv32;            

    /* 串口从空闲开始计数,=500时产生超时中断 */
    stcTimerCfg.Tim0_CmpValue         = 500;  // 1000; //         
    TIMER0_BaseInit (M4_TMR01, Tim0_ChannelB, &stcTimerCfg);

    /* 清除标志位 */
    TIMER0_ClearFlag (M4_TMR01, Tim0_ChannelB);

    /* 这几个参数没有深入研究,是直接从官网例程中提取的 */
    StcTimer0TrigInit.Tim0_InTrigEnable = false;
    StcTimer0TrigInit.Tim0_InTrigClear  = true;
    StcTimer0TrigInit.Tim0_InTrigStart  = true;
    StcTimer0TrigInit.Tim0_InTrigStop   = false;
    TIMER0_HardTriggerInit (M4_TMR01, Tim0_ChannelB, &StcTimer0TrigInit);
}

/* dma初始化 */
static int hal_uart_dma_init (void)
{
    /* 使能DMA1时钟 */
    PWC_Fcg0PeriphClockCmd (PWC_FCG0_PERIPH_DMA1, Enable)

    /* 使能 DMA1. */
    DMA_Cmd (M4_DMA1, Enable);

    return 0;
}

/* dma接受使能 */
int uart_dma_rx_start (uint8_t * buf, uint32_t len)
{
    stc_dma_config_t stcDmaInit;
    stc_irq_regi_conf_t stcIrqRegiCfg;

    /* Initialize DMA. */
    MEM_ZERO_STRUCT (stcDmaInit);

    /* 传输大小,0=1024bytes 1=2048bytes,我理解是传输的最大数据长度 */
    stcDmaInit.u16BlockSize           = 1u;   

    /* 接收缓存长度 */                             
    stcDmaInit.u16TransferCnt         = (uint16_t)len;      

    /* 配置DMA源,这里选择UART2的接收寄存器 */               
    stcDmaInit.u32SrcAddr             = ((uint32_t)(&M4_USART2->DR) + 2ul);

    /* 接收缓存地址 */
    stcDmaInit.u32DesAddr             = (uint32_t)(buf);   

    /* 源地址固定 */               
    stcDmaInit.stcDmaChCfg.enSrcInc   = AddressFix;

    /* 接收缓存地址递增 */                       
    stcDmaInit.stcDmaChCfg.enDesInc   = AddressIncrease;                  
    stcDmaInit.stcDmaChCfg.enIntEn    = Enable;   /* 使能中断 */
    stcDmaInit.stcDmaChCfg.enTrnWidth = Dma8Bit;  /* 传输数据宽度8bit */
    DMA_InitChannel (M4_DMA1, DmaCh0, &stcDmaInit);

     /* 使能DMA1通道0,这个可以通过参考手册查阅uart对应的dma通道 */
    DMA_ChannelCmd (M4_DMA1, DmaCh0, Enable);     

    DMA_ClearIrqFlag(M4_DMA1, DmaCh0, TrnCpltIrq); /* 清除标记位 */

    PWC_Fcg0PeriphClockCmd (PWC_FCG0_PERIPH_AOS, Enable); /* 启用外围电路触发功能 */

    /* 配置传输触发源,这里选择UART2的数据接收 */
    DMA_SetTriggerSrc (M4_DMA1, DmaCh0, EVT_USART2_RI);   

    stcIrqRegiCfg.enIRQn      = Int002_IRQn;          /* DMA1通道0完成中断号 */
    stcIrqRegiCfg.pfnCallback = &dma_ch0_rx_tc_cb;    /* DMA传输完成中断回调函数 */
    stcIrqRegiCfg.enIntSrc    = INT_DMA1_TC0;         /* DMA1通道0传输完成中断向量号 */
    enIrqRegistration (&stcIrqRegiCfg);

    NVIC_SetPriority(stcIrqRegiCfg.enIRQn, DDL_IRQ_PRIORITY_00);
    NVIC_ClearPendingIRQ(stcIrqRegiCfg.enIRQn);
    NVIC_EnableIRQ(stcIrqRegiCfg.enIRQn);

    return 0;
}

/* dma发送使能 */
int uart_dma_tx_start (uint8_t * buf, uint32_t len)
{
    stc_dma_config_t stcDmaInit;
    stc_irq_regi_conf_t stcIrqRegiCfg;

    USART_FuncCmd (M4_USART2, UsartTx, Disable);           /* 失能串口发送 */

    MEM_ZERO_STRUCT (stcDmaInit);
    /* 传输大小,0=1024bytes 1=2048bytes,我理解是传输的最大数据长度 */
    stcDmaInit.u16BlockSize           = 1u;   
        
    /* 发送数据长度 */               
    stcDmaInit.u16TransferCnt         = (uint16_t)len;

    /* 配置DMA源=发送缓存首地址 */
    stcDmaInit.u32SrcAddr             = (uint32_t)(buf);   

    /* 目标地址=UART2的发送寄存器 */           
    stcDmaInit.u32DesAddr             = ((uint32_t)(&M4_USART2->DR));  
    stcDmaInit.stcDmaChCfg.enSrcInc   = AddressIncrease;   /* 源地址递增 */
    stcDmaInit.stcDmaChCfg.enDesInc   = AddressFix;        /* 目标地址固定 */
    stcDmaInit.stcDmaChCfg.enIntEn    = Enable;            /* 使能中断 */
    stcDmaInit.stcDmaChCfg.enTrnWidth = Dma8Bit;           /* 传输数据宽度8bit */
    DMA_InitChannel (M4_DMA1, DmaCh1, &stcDmaInit);

    DMA_ClearIrqFlag(M4_DMA1, DmaCh1, TrnCpltIrq);             /* 清除标记位 */

    PWC_Fcg0PeriphClockCmd (PWC_FCG0_PERIPH_AOS, Enable);      /* 启用外围电路触发功能 */

    /* 配置传输触发源,这里选择UART2的数据发送 */
    DMA_SetTriggerSrc (M4_DMA1, DmaCh1, EVT_USART2_TI);        

    stcIrqRegiCfg.enIRQn      = DMA1_CH1_TC_IRQn;     /* DMA1通道1完成中断号 */
    stcIrqRegiCfg.pfnCallback = &dma_ch1_tx_tc_cb;    /* DMA传输完成中断回调函数 */
    stcIrqRegiCfg.enIntSrc    = DMA1_CH1_TC_NUM;      /* DMA1通道1完成中断向量号 */
    enIrqRegistration (&stcIrqRegiCfg);

    NVIC_SetPriority(stcIrqRegiCfg.enIRQn, DDL_IRQ_PRIORITY_00);
    NVIC_ClearPendingIRQ(stcIrqRegiCfg.enIRQn);
    NVIC_EnableIRQ(stcIrqRegiCfg.enIRQn);

    /* 使能DMA1通道1,这个可以通过参考手册查阅uart对应的dma通道 */
    DMA_ChannelCmd (M4_DMA1, DmaCh1, Enable);

    /* 使能串口发送 */
    USART_FuncCmd (M4_USART2, UsartTx, Enable);                 

    return 0;
}

/* dma接收完成中断回调函数 */
static void dma_ch0_rx_tc_cb (void)
{
    DMA_ClearIrqFlag (M4_DMA1, DmaCh0, BlkTrnCpltIrq);
}

/* dma发送完成中断回调函数 */
static void dma_ch1_tx_tc_cb (void)
{
    DMA_ClearIrqFlag (M4_DMA1, DmaCh1, BlkTrnCpltIrq);
    extern void uart_evt_w_tc_send (void);
    uart_evt_w_tc_send ();
}

/* gpio初始化 */
static int hal_uart_gpio_init (void)
{
    PORT_SetFunc (PortA, Pin10, Func_Usart2_Rx, Disable);
    PORT_SetFunc (PortA, Pin09, Func_Usart2_Tx, Disable);

    return 0;
}

/******************************************************************************************************
* name    : hal_uart_init
* fuction : uart底层硬件初始化
* author  : cong
* time    : 2020-11-24
* input   : re_buf --> 注册接收缓存
*           len    --> 缓存长度
*           baude  --> 波特率
* output  :
* version : v1.00
* other   :
******************************************************************************************************/
int hal_uart_init (uint8_t *re_buf, uint16_t len, uint32_t baude)
{
    int ret  = 0;

    uart_parm.rx_buf = re_buf;
    uart_parm.rx_len = len;

    timer0b_init ();
    hal_uart_gpio_init ();
    ret = hal_uart_conf_init (baude);
    hal_uart_dma_init ();
    uart_dma_rx_start (uart_parm.rx_buf, uart_parm.rx_len);

    return ret;
}

使用特权

评论回复
13
wiba| | 2022-11-1 14:34 | 只看该作者
串口接收使用DMA方案,配合使用UART的超时中断来使用(STM32有串口闲中断更好用)

使用特权

评论回复
14
jcky001| | 2022-11-21 11:08 | 只看该作者
官网有现成的例程可以参考

使用特权

评论回复
15
jinyiheng|  楼主 | 2022-12-12 12:09 | 只看该作者
谢谢各位的指导,已经通过测试了

使用特权

评论回复
16
yorkbarney| | 2023-1-5 11:58 | 只看该作者
网上不是有相关的教程可以参考的吗

使用特权

评论回复
17
macpherson| | 2023-1-5 15:39 | 只看该作者
如果连续字符超过一定的时间,就认为这个数据接收完成了。

使用特权

评论回复
18
uptown| | 2023-1-5 16:07 | 只看该作者
这个不能使用定时器判断的吗?              

使用特权

评论回复
19
janewood| | 2023-1-6 14:30 | 只看该作者
计数超时,然后判断接收完成。              

使用特权

评论回复
20
mollylawrence| | 2023-1-6 17:10 | 只看该作者
参考正点原子的做法。              

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

3

主题

27

帖子

2

粉丝