|
【小华HC32F48测评】关于通用定时器time0、adc、DMA的学习与测试
[复制链接]
- 定时器time0的学习与测试
- 打开example文件里里time0的文件夹,打开time0_capture工程,其示例功能如下,简单来说就是定时器time0循环技术,每次计数溢出就让红灯点亮一段时间后熄灭,然后任意时间按ky5,蓝色灯会亮
- time0的定义:通用定时器 0(Timer0)是一个可以实现同步计数和异步计数方式的基本定时器。该定时器内含 2 个 通道(CH-A 和 CH-B),可以在计数期间产生比较匹配事件与计数溢出事件。该事件可以触发中断,也 可以用于触发其他模块动作
- 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
-
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 (;;) {
;
}
}
- 效果如下:
- ADC_DMA测试:
- 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)
- 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
- 初始化函数:主要是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,如下图所述:
-
效果:能精确到小数点三位,非常精确
-
对HC包含的LL库开发各类串口功能初始化的简单总结:
-
开发中最重要头文件是hc32f448,定义了所有串口和功能,是所有Pin口功能的基础配置。
-
从前面定时器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的结构体指针,常需要设置波特率。
-
在配置这些串口功能的函数中:
第一步:定义串口功能的结构体指针及中断结构体指针;同时关闭外设读写保护(如果有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);
如下图为示例:
以上为本次测评学习。
|
|