2445|2

61

帖子

0

TA的资源

一粒金砂(中级)

楼主
 

【小华HC32F48测评】关于通用定时器time0、adc、DMA的学习与测试 [复制链接]

 
  1. 定时器time0的学习与测试
    1. 打开example文件里里time0的文件夹,打开time0_capture工程,其示例功能如下,简单来说就是定时器time0循环技术,每次计数溢出就让红灯点亮一段时间后熄灭,然后任意时间按ky5,蓝色灯会亮
    2. time0的定义:通用定时器 0(Timer0)是一个可以实现同步计数和异步计数方式的基本定时器。该定时器内含 2 个 通道(CH-A 和 CH-B),可以在计数期间产生比较匹配事件与计数溢出事件。该事件可以触发中断,也 可以用于触发其他模块动作
           
    3. time0一般需要的宏定义
      为了方便,我把注释一起写在代码行里;time0的基本操作是对三个寄存器的操作:CNTAR(计数值寄存器),BCONR(基本控制寄存器),STFLR(状态标志寄存器
      /* TMR0 unit and channel definition */
      //time0初始化的宏定义
      #define TMR0_UNIT                       (CM_TMR0_2)
      //宏定义time0的基地址,基地址位置可以看下一张图片,有类似定义有ADC,AES,CMP,USART,请看hc32f448.h
      #define TMR0_CLK                        (FCG2_PERIPH_TMR0_2)
      //使能time0的时钟
      #define TMR0_CH                         (TMR0_CH_A)
      //选择time0通道A
      #define TMR0_TRIG_CH                    (AOS_TMR0)
      //使用内部硬件触发功能,根据资料书所属,需要吧AOS功能控制位使能(自动运行系统使能)
      #define TMR0_CH_INT                     (TMR0_INT_CMP_A | TMR0_INT_OVF_A)
      //使能通道A的计数中断宏定义,CMP_A是计数匹配,OVF是计数溢出
      #define TMR0_CH_CMP_FLAG                (TMR0_FLAG_CMP_A)
      //计数匹配标志
      
      //前面两个宏定义的区别在于对底层的寄存器操作的不一样,TMP0_CH_INT操作的是寄存器BCONR(基本控制寄存器),FLAG操作的是STFLR(状态标志寄存器)
      
      #define TMR0_INT_CMP_SRC                (INT_SRC_TMR0_2_CMP_A)
      //计数匹配地址
      #define TMR0_CMP_IRQn                   (INT006_IRQn)
      //计数匹配中断位
      #define TMR0_CH_OVF_FLAG                (TMR0_FLAG_OVF_A)
      //溢出标志
      #define TMR0_INT_OVF_SRC                (INT_SRC_TMR0_2_OVF_A)
      //溢出地址
      #define TMR0_OVF_IRQn                   (INT007_IRQn)
      //溢出中断位
      

       
      图1-1
         
      图1-2

    4. tiem0中断函数:
      注释依旧在代码中

      /**
       * [url=home.php?mod=space&uid=159083]@brief[/url] TMR0 capture interrupt callback function.
       * @param  None
       * @retval None
       */
      static void TMR0_CaptureIrqCallback(void)//硬件触发,即key5按下后的中断函数
      {
          BSP_LED_Toggle(LED_BLUE);//翻转LED状态
          TMR0_ClearStatus(TMR0_UNIT, TMR0_CH_CMP_FLAG);//清除计数匹配标志位
      }
      
      static void TMR0_OverFlowIrqCallback(void)/溢出中断函数
      {
          BSP_LED_Toggle(LED_RED);//每次计数溢出,翻转红灯状态一次
          TMR0_ClearStatus(TMR0_UNIT, TMR0_CH_OVF_FLAG);//清除计数溢出标志位
      }
      
      /**
       * @brief  Configure TMR0.
       * @note   In asynchronous clock, If you want to write a TMR0 register, you need to wait for
       *         at least 3 asynchronous clock cycles after the last write operation!
       * @param  None
       * @retval None
       */
      static void TMR0_Config(void)
      {
          stc_tmr0_init_t stcTmr0Init;//time0的结构体指针
          stc_irq_signin_config_t stcIrqSignConfig;//中断配置指针
      
          /* Enable timer0 and AOS clock */
          FCG_Fcg2PeriphClockCmd(TMR0_CLK, ENABLE);//使能time0时钟
          FCG_Fcg0PeriphClockCmd(FCG0_PERIPH_AOS, ENABLE);
      //使能自动运行系统AOS,用以配置硬件触发
      
          /* TIMER0 initialize */
          (void)TMR0_StructInit(&stcTmr0Init);//指针初始化
          stcTmr0Init.u32ClockSrc = TMR0_CLK_SRC_INTERN_CLK;//时钟
          stcTmr0Init.u32ClockDiv = TMR0_CLK_DIV512;//分频
          stcTmr0Init.u32Func     = TMR0_FUNC_CAPT;
          //TMR0_FUNC_CAPT:Input capture function ,即输入捕获功能,同时还有输出比较功能
      
          (void)TMR0_Init(TMR0_UNIT, TMR0_CH, &stcTmr0Init);
         //选用通道A
      
          TMR0_IntCmd(TMR0_UNIT, TMR0_CH_INT, ENABLE);
         //使能计数匹配
      
          AOS_SetTriggerEventSrc(TMR0_TRIG_CH, BSP_KEY_KEY5_EVT);
         //令key5事件和硬件触发功能绑定,每次按按键就会触发内部硬件time0
      
          /* Interrupt configuration */
         //中断结构体配置
          stcIrqSignConfig.enIntSrc    = TMR0_INT_CMP_SRC;//使能计数匹配中断
          stcIrqSignConfig.enIRQn      = TMR0_CMP_IRQn;//计数匹配中断号
          stcIrqSignConfig.pfnCallback = &TMR0_CaptureIrqCallback;//中断捕获函数回调
          (void)INTC_IrqSignIn(&stcIrqSignConfig);//
          NVIC_ClearPendingIRQ(stcIrqSignConfig.enIRQn);
          NVIC_SetPriority(stcIrqSignConfig.enIRQn, DDL_IRQ_PRIO_DEFAULT);
          NVIC_EnableIRQ(stcIrqSignConfig.enIRQn);
      
          stcIrqSignConfig.enIntSrc    = TMR0_INT_OVF_SRC;//使能技术溢出中断
          stcIrqSignConfig.enIRQn      = TMR0_OVF_IRQn;
          stcIrqSignConfig.pfnCallback = &TMR0_OverFlowIrqCallback;//溢出中断函数
          (void)INTC_IrqSignIn(&stcIrqSignConfig);
          NVIC_ClearPendingIRQ(stcIrqSignConfig.enIRQn);
          NVIC_SetPriority(stcIrqSignConfig.enIRQn, DDL_IRQ_PRIO_DEFAULT);
          NVIC_EnableIRQ(stcIrqSignConfig.enIRQn);//使能
      }
      
      /**
       * @brief  Main function of example project
       * @param  None
       * @retval int32_t return value, if needed
       */
      int32_t main(void)
      {
          /* Peripheral registers write unprotected */
          LL_PERIPH_WE(EXAMPLE_PERIPH_WE);//解除外设寄存器保护
          /* BSP init */
          BSP_IO_Init();
          BSP_LED_Init();
          BSP_KEY_Init();
          /* Configure TMR0 */
          TMR0_Config();
          /* TMR0 start counting */
          TMR0_Start(TMR0_UNIT, TMR0_CH);//启动time0计数
          /* Peripheral registers write protected */
          LL_PERIPH_WP(EXAMPLE_PERIPH_WP);
      
          for (;;) {
              ;
          }
      }
    5. 效果如下:
       
  2. ADC_DMA测试:
    1. ADC宏定义:主要定义内容:定义选用哪个ADC通道,同时定义对应需要使能的时钟,定义对应通道的Pin口,包括输入输出,
      /* ADC unit instance for this example. */
      #define ADC_UNIT                        (CM_ADC1)
      #define ADC_PERIPH_CLK                  (FCG3_PERIPH_ADC1)
      
      /* Selects ADC channels that needed. */
      #define ADC_CHX                         (ADC_CH3)
      #define ADC_CHX_PORT                    (GPIO_PORT_A)
      #define ADC_CHX_PIN                     (GPIO_PIN_03)
      
      #define ADC_CHY                         (ADC_CH10)
      #define ADC_CHY_PORT                    (GPIO_PORT_C)
      #define ADC_CHY_PIN                     (GPIO_PIN_00)
      
      #define ADC_CHZ                         (ADC_CH11)
      #define ADC_CHZ_PORT                    (GPIO_PORT_C)
      #define ADC_CHZ_PIN                     (GPIO_PIN_01)
      
      #define ADC_CH_MIN                      (ADC_CHX)
      #define ADC_CH_MAX                      (ADC_CHZ)
      #define ADC_DR_START                    ((uint32_t)&ADC_UNIT->DR3)
      #define PTTM_VAL_IDX                    (7U)
      
      /* ADC sequence to be used. */
      #define ADC_SEQ                         (ADC_SEQ_A)
      
      /* Hard trigger of the specified sequence. */
      #define ADC_SEQ_HARDTRIG                (ADC_HARDTRIG_ADTRG_PIN)
      #define ADC_SEQ_TRIG_PORT               (GPIO_PORT_E)
      #define ADC_SEQ_TRIG_PIN                (GPIO_PIN_14)
      #define ADC_SEQ_TRIG_PIN_FUNC           (GPIO_FUNC_1)
      
    2. DMA宏定义:其中BTC指的是块传输完成中断位,保存在中断寄存器(DMA_INTSTAT1)中
      /**
       * Definitions of DMA.
       * 'APP_DMA_BLOCK_SIZE': 1~1024, inclusive. 1~16 for ADC1; 1~8 for ADC2; 1~12 for ADC3.
       * 'APP_DMA_TRANS_COUNT': 0~65535, inclusive. 0: always transmit.
       */
      #define DMA_UNIT                        (CM_DMA1)
      #define DMA_PERIPH_CLK                  (FCG0_PERIPH_DMA1)
      #define DMA_CH                          (DMA_CH0)
      #define DMA_AOS_TRIG_SEL                (AOS_DMA1_0)
      //触发事件后DMA读取数据
      
      #define DMA_TRANS_CNT                   (0U)
      #define DMA_BLOCK_SIZE                  (ADC_CH_MAX - ADC_CH_MIN + 1U)
      #define DMA_DATA_WIDTH                  (DMA_DATAWIDTH_16BIT)
      #define DMA_SRC_ADDR                    ADC_DR_START
      //读取各通道数据寄存器 ADC_DR
      #define DMA_DEST_ADDR                   ((uint32_t)(&m_au16AdcValue[0U]))
      
      #define DMA_TRIG_EVT                    (EVT_SRC_ADC1_EOCA)
      //ADC触发中断事件
      
      #define DMA_INT_TYPE                    (DMA_INT_BTC_CH0)
      #define DMA_INT_IRQn                    (DMA1_TC0_BTC0_IRQn)
      #define DMA_INT_PRIO                    (DDL_IRQ_PRIO_03)
      #define DMA_INT_FLAG                    (DMA_FLAG_BTC_CH0)
      #define DMA_IRQ_HANDLER                 DMA1_TC0_BTC0_Handler
      
    3. 初始化函数:主要是adc的Pin口功能初始化,硬件触发adc扫描Pin口,DMA初始化,产生ADC_EOC事件。
      /**
       * @brief  ADC configuration.
       * @param  None
       * @retval None
       */
      static void AdcConfig(void)
      {
          AdcInitConfig();
          DmaConfig();
          AdcHardTriggerConfig();
      }
      
      /**
       * @brief  Initializes ADC.
       * @param  None
       * @retval None
       */
      static void AdcInitConfig(void)
      {
          stc_adc_init_t stcAdcInit;
      
          /* 1. Enable ADC peripheral clock. */
          FCG_Fcg3PeriphClockCmd(ADC_PERIPH_CLK, ENABLE);
          /* 2. Modify the default value depends on the application. */
          (void)ADC_StructInit(&stcAdcInit);
          /* 3. Initializes ADC. */
          (void)ADC_Init(ADC_UNIT, &stcAdcInit);
          /* 4. ADC channel configuration. */
          /* 4.1 Set the ADC pin to analog input mode. */
          AdcSetPinAnalogMode();
          /* 4.2 Enable ADC channels. */
          ADC_ChCmd(ADC_UNIT, ADC_SEQ, ADC_CHX, ENABLE);
          ADC_ChCmd(ADC_UNIT, ADC_SEQ, ADC_CHY, ENABLE);
          ADC_ChCmd(ADC_UNIT, ADC_SEQ, ADC_CHZ, ENABLE);
      }
      
      /**
       * @brief  Set specified ADC pin to analog mode.
       * @param  None
       * @retval None
       */
      static void AdcSetPinAnalogMode(void)
      {
          stc_gpio_init_t stcGpioInit;
      
          (void)GPIO_StructInit(&stcGpioInit);
          stcGpioInit.u16PinAttr = PIN_ATTR_ANALOG;
          (void)GPIO_Init(ADC_CHX_PORT, ADC_CHX_PIN, &stcGpioInit);
          (void)GPIO_Init(ADC_CHY_PORT, ADC_CHY_PIN, &stcGpioInit);
          (void)GPIO_Init(ADC_CHZ_PORT, ADC_CHZ_PIN, &stcGpioInit);
      }
      
      /**
       * @brief  ADC hard trigger configuration.
       * @param  None
       * @retval None
       */
      static void AdcHardTriggerConfig(void)
      {
          GPIO_SetFunc(ADC_SEQ_TRIG_PORT, ADC_SEQ_TRIG_PIN, ADC_SEQ_TRIG_PIN_FUNC);
          ADC_TriggerConfig(ADC_UNIT, ADC_SEQ, ADC_SEQ_HARDTRIG);
          ADC_TriggerCmd(ADC_UNIT, ADC_SEQ, ENABLE);
      }
      
      /**
       * @brief  DMA configuration.
       * @param  None
       * @retval None
       */
      static void DmaConfig(void)
      {
          stc_dma_init_t stcDmaInit;
          stc_dma_repeat_init_t stcDmaRptInit;
      
          (void)DMA_StructInit(&stcDmaInit);
          stcDmaInit.u32IntEn       = DMA_INT_ENABLE;
          stcDmaInit.u32SrcAddr     = DMA_SRC_ADDR;
          stcDmaInit.u32DestAddr    = DMA_DEST_ADDR;
          stcDmaInit.u32DataWidth   = DMA_DATA_WIDTH;
          stcDmaInit.u32BlockSize   = DMA_BLOCK_SIZE;
          stcDmaInit.u32TransCount  = DMA_TRANS_CNT;
          stcDmaInit.u32SrcAddrInc  = DMA_SRC_ADDR_INC;
          stcDmaInit.u32DestAddrInc = DMA_DEST_ADDR_INC;
          /* Enable DMA peripheral clock and AOS function. */
          FCG_Fcg0PeriphClockCmd(DMA_PERIPH_CLK, ENABLE);
          (void)DMA_Init(DMA_UNIT, DMA_CH, &stcDmaInit);
      
          stcDmaRptInit.u32Mode      = DMA_RPT_BOTH;
          stcDmaRptInit.u32SrcCount  = DMA_BLOCK_SIZE;
          stcDmaRptInit.u32DestCount = DMA_BLOCK_SIZE;
          (void)DMA_RepeatInit(DMA_UNIT, DMA_CH, &stcDmaRptInit);
      
          /* Enable AOS clock */
          FCG_Fcg0PeriphClockCmd(FCG0_PERIPH_AOS, ENABLE);
          /* Set DMA trigger source */
          AOS_SetTriggerEventSrc(DMA_AOS_TRIG_SEL, DMA_TRIG_EVT);
          /* DMA IRQ configuration. */
          DmaIrqConfig();
          DMA_Cmd(DMA_UNIT, ENABLE);
          DMA_ChCmd(DMA_UNIT, DMA_CH, ENABLE);
      }
      
      /**
       * @brief  DMA interrupt configuration.
       * @param  None
       * @retval None
       */
      static void DmaIrqConfig(void)
      {
          DMA_ClearTransCompleteStatus(DMA_UNIT, DMA_INT_FLAG);
          /* NVIC setting */
          NVIC_ClearPendingIRQ(DMA_INT_IRQn);
          NVIC_SetPriority(DMA_INT_IRQn, DMA_INT_PRIO);
          NVIC_EnableIRQ(DMA_INT_IRQn);
      }
      
      /**
       * @brief  DMA IRQ handler.
       * @param  None
       * @retval None
       */
      void DMA_IRQ_HANDLER(void)
      {
          if (DMA_GetTransCompleteStatus(DMA_UNIT, DMA_INT_FLAG) == SET) {
              DMA_ClearTransCompleteStatus(DMA_UNIT, DMA_INT_FLAG);
              m_u8AdcValUpdated = 1U;
          }
      
          __DSB();  /* Arm Errata 838869 */
      }

      若需要ADC连续扫描,就把STRT位写1,如下图所述:

         

    4. 效果:能精确到小数点三位,非常精确

       
       

  3. 对HC包含的LL库开发各类串口功能初始化的简单总结:

    1. 开发中最重要头文件是hc32f448,定义了所有串口和功能,是所有Pin口功能的基础配置。

       

    2. 从前面定时器time0和adc的例程中我们可以发现,把Pin口初始化成每一类功能时候,都会有对应的初始化结构体指针
      如stc_adc_init_t       stc_dma_init_t    stc_gpio_init_t,基本格式为:stc_xxx_init_t;
      这些结构体指针的定义都藏在对应的ll库头文件中,这些头文件统一定义名为:hc32_ll_xxx.h,当我们需要什么串口的功能的时候,就要去找到对应的结构体指针,然后根据这些结构体指针里的参数进行设置,就如USART的结构体指针,常需要设置波特率。

    3. 在配置这些串口功能的函数中:
      第一步:定义串口功能的结构体指针及中断结构体指针;同时关闭外设读写保护(如果有LL_PERIPH_WE和WP)
      第二步:打开对应串口或功能的时钟允许(常放在hc32_ll_fcg.c中),
      第三步:对结构体指针内的参数按手册要求进行配置,其对应的配置函数放在了hc32_ll_xxx.c中,其中命名格式如 xxx_Init 或 xxx_cmd 的函数是通常是必须要有的
      第四步:如果有中断,就配置中断结构体指针和中断函数,中断结构体指针为:stc_irq_signin_config_t,通常需要配置的有enIRQn,enIntSrc,pfnCallback,enIntSrc是对应串口中断数(在hc32f448中600行左右),enIRQn是中断号(也在hc32f448中,221行左右),pfnCallback是回调函数(可自定义,正常是void返回类型),配置中断需要  下面三个函数,做用是使能中断,清除中断,中断优先级。

          NVIC_ClearPendingIRQ(stcIrqSignConfig.enIRQn);
          NVIC_SetPriority(stcIrqSignConfig.enIRQn, DDL_IRQ_PRIO_DEFAULT);
          NVIC_EnableIRQ(stcIrqSignConfig.enIRQn);

      第五步:打开外设读写保护    LL_PERIPH_WP(LL_PERIPH_SEL);
      如下图为示例:

       

      以上为本次测评学习。

最新回复

请问上面的例程中对ADC的EOCF标志位是否需要清零,如果要 那程序在哪里呢   详情 回复 发表于 2023-9-6 20:58
点赞 关注(1)
 
 

回复
举报

6993

帖子

11

TA的资源

版主

沙发
 

第一步:定义串口功能的结构体指针及中断结构体指针;同时关闭外设读写保护(如果有LL_PERIPH_WE和WP)
第二步:打开对应串口或功能的时钟允许(常放在hc32_ll_fcg.c中),
第三步:对结构体指针内的参数按手册要求进行配置,其对应的配置函数放在了hc32_ll_xxx.c中,其中命名格式如 xxx_Init 或 xxx_cmd 的函数是通常是必须要有的
第四步:如果有中断,就配置中断结构体指针和中断函数,中断结构体指针为:stc_irq_signin_config_t,通常需要配置的有enIRQn,enIntSrc,pfnCallback,enIntSrc是对应串口中断数(在hc32f448中600行左右),enIRQn是中断号(也在hc32f448中,221行左右),pfnCallback是回调函数(可自定义,正常是void返回类型),配置中断需要  下面三个函数,做用是使能中断,清除中断,中断优先级。

谢谢分享精彩内容、

 
 
 

回复

85

帖子

0

TA的资源

一粒金砂(高级)

板凳
 

请问上面的例程中对ADC的EOCF标志位是否需要清零,如果要 那程序在哪里呢

 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/8 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表