本帖最后由 lgnstar 于 2022-9-21 10:04 编辑
首先感谢21ic和合泰能给我这次测评的机会!
此次测试内容为使用ADC采集模拟数据并显示在4位数码管上,采用ADC+PDMA方式,模拟量使用ESK32-21001底板的Potentiometer电位计获得。
核心板需要与底板连接3根线, VDD33、VSS、Potentiometer(VR)。我在焊连接器插针的时候脑子短路,把连接器焊反了,只能使用连接线了。
项目工程直接使用\HT32_STD_5xxxx_FWLib_V1.1.1_5938\project_template\IP\Example\MDK_ARMv5\Project_54253.uvprojx修改。
这里使用软件触发ADC,PDMA循环模式,初始化程序如下:
static void PDMA_Configuration(void)
{
{ /* Enable peripheral clock */
CKCU_PeripClockConfig_TypeDef CKCUClock = {{ 0 }};
CKCUClock.Bit.PDMA = 1;
CKCU_PeripClockConfig(CKCUClock, ENABLE);
}
{ /* Configure PDMA channel to move ADC result from ADC->DR[0] to TM CHnCCR */
PDMACH_InitTypeDef PDMACH_InitStructure;
PDMACH_InitStructure.PDMACH_SrcAddr = (u32)&HTCFG_ADC_PORT->DR[0];
PDMACH_InitStructure.PDMACH_DstAddr = (u32)(adc_buf); //采样数据缓冲区
PDMACH_InitStructure.PDMACH_BlkCnt = 1;
PDMACH_InitStructure.PDMACH_BlkLen = ADC_SAMPLE_CNT; //连续采样数据个数
PDMACH_InitStructure.PDMACH_DataSize = WIDTH_16BIT;
PDMACH_InitStructure.PDMACH_Priority = VH_PRIO;
PDMACH_InitStructure.PDMACH_AdrMod = SRC_ADR_FIX | DST_ADR_LIN_INC | AUTO_RELOAD;
PDMA_Config(HTCFG_DMA_PORT, &PDMACH_InitStructure);
PDMA_EnaCmd(HTCFG_DMA_PORT, ENABLE);
}
}
static void ADC_Configuration(void)
{
{ /* Enable peripheral clock */
CKCU_PeripClockConfig_TypeDef CKCUClock = {{ 0 }};
CKCUClock.Bit.AFIO = 1;
CKCUClock.Bit.HTCFG_ADC_IPN = 1;
CKCU_PeripClockConfig(CKCUClock, ENABLE);
}
/* Configure AFIO mode as ADC function */
AFIO_GPxConfig(HTCFG_VR_GPIO_ID, HTCFG_VR_AFIO_PIN, HTCFG_VR_AFIO_MODE);
{ /* ADC related settings */
/* CK_ADC frequency is set to (CK_AHB / 64) */
CKCU_SetADCnPrescaler(HTCFG_ADC_CKCU_ADCPRE, CKCU_ADCPRE_DIV64);
/* One Shot mode, sequence length = 1 */
//ADC_RegularGroupConfig(HTCFG_ADC_PORT, ONE_SHOT_MODE, 1, 0);
ADC_RegularGroupConfig(HTCFG_ADC_PORT, CONTINUOUS_MODE, 1, 0);
/* ADC conversion time = (Sampling time + Latency) / CK_ADC = (1.5 + ADST + 12.5) / CK_ADC */
/* Set ADST = 0, sampling time = 1.5 + ADST */
#if (LIBCFG_ADC_SAMPLE_TIME_BY_CH)
// The sampling time is set by the last parameter of the function "ADC_RegularChannelConfig()".
#else
ADC_SamplingTimeConfig(HTCFG_ADC_PORT, 0);
#endif
/* Set ADC conversion sequence as channel n */
ADC_RegularChannelConfig(HTCFG_ADC_PORT, HTCFG_VR_ADC_CH, 0, 0);
#if 1
/* Set TM MTO as ADC trigger source */
//ADC_RegularTrigConfig(HTCFG_ADC_PORT, HTCFG_ADC_TRIG_TM);
ADC_RegularTrigConfig(HTCFG_ADC_PORT, ADC_TRIG_SOFTWARE); //使能软件触发转换
#endif
}
/* Issue ADC DMA request when cycle end of conversion occur */
ADC_PDMAConfig(HTCFG_ADC_PORT, ADC_PDMA_REGULAR_CYCLE, ENABLE); //使能连续模式
ADC_Cmd(HTCFG_ADC_PORT, ENABLE);
ADC_SoftwareStartConvCmd(HTCFG_ADC_PORT, ENABLE); //触发ADC开始转换
}
ADC转换开始后就会不间断的进行转换,转换结果会放入adc_buf缓冲区,循环更新。
接下来及就是在数码管上显示ADC转换的结果。这里只显示ADC转换后的值(0~4095)。
const u8 NumberChar[]={
/* a: Seg4(0x10), b: Seg7(0x80), c: Seg2(0x04), d: Seg5(0x20),
e: Seg3(0x08), f: Seg0(0x01), g: Seg6(0x40), dp: Seg1(0x02) */
0xBD, /* '0' = a+b+c+d+e+f = 0x10 + 0x80 + 0x04 + 0x20 + 0x08 + 0x01 = 0xBD */
0x84, /* '1' = b+c+ = 0x80 + 0x04 = 0x84 */
0xF8, /* '2' = a+b +d+e +g = 0x10 + 0x80 + 0x20 + 0x08 + + 0x40 = 0xF8 */
0xF4, /* '3' = a+b+c+d +g = 0x10 + 0x80 + 0x04 + 0x20 + + 0x40 = 0xF4 */
0xC5, /* '4' = b+c +f+g = 0x80 + 0x04 + 0x01 + 0x40 = 0xC5 */
0x75, /* '5' = a +c+d +f+g = 0x10 + 0x04 + 0x20 + 0x01 + 0x40 = 0x75 */
0x7D, /* '6' = a +c+d+e+f+g = 0x10 + 0x04 + 0x20 + 0x08 + 0x01 + 0x40 = 0x7D */
0x95, /* '7' = a+b+c +f = 0x10 + 0x80 + 0x04 + 0x01 = 0x95 */
0xFD, /* '8' = a+b+c+d+e+f+g = 0x10 + 0x80 + 0x04 + 0x20 + 0x08 + 0x01 + 0x40 = 0xFD */
0xF5, /* '9' = a+b+c+d +f+g = 0x10 + 0x80 + 0x04 + 0x20 + 0x01 + 0x40 = 0xF5 */
0x02 /* '.' = dp = 0x02 = 0x02 */
};
/*********************************************************************************************************//**
* [url=home.php?mod=space&uid=247401]@brief[/url] Configure the LEDC.
* @retval None
***********************************************************************************************************/
void bsp_ledc_config(void)
{
{
/* Turn on the APB clock of AFIO. */
CKCU_PeripClockConfig_TypeDef CKCUClock = {{0}};
CKCUClock.Bit.AFIO = 1;
CKCU_PeripClockConfig(CKCUClock, ENABLE);
/* SEG0~7 */
AFIO_GPxConfig(HTCFG_LEDC_SEG0_GPIO_ID, HTCFG_LEDC_SEG0_AFIO_PIN, AFIO_FUN_LEDC);
AFIO_GPxConfig(HTCFG_LEDC_SEG1_GPIO_ID, HTCFG_LEDC_SEG1_AFIO_PIN, AFIO_FUN_LEDC);
AFIO_GPxConfig(HTCFG_LEDC_SEG2_GPIO_ID, HTCFG_LEDC_SEG2_AFIO_PIN, AFIO_FUN_LEDC);
AFIO_GPxConfig(HTCFG_LEDC_SEG3_GPIO_ID, HTCFG_LEDC_SEG3_AFIO_PIN, AFIO_FUN_LEDC);
AFIO_GPxConfig(HTCFG_LEDC_SEG4_GPIO_ID, HTCFG_LEDC_SEG4_AFIO_PIN, AFIO_FUN_LEDC);
AFIO_GPxConfig(HTCFG_LEDC_SEG5_GPIO_ID, HTCFG_LEDC_SEG5_AFIO_PIN, AFIO_FUN_LEDC);
AFIO_GPxConfig(HTCFG_LEDC_SEG6_GPIO_ID, HTCFG_LEDC_SEG6_AFIO_PIN, AFIO_FUN_LEDC);
AFIO_GPxConfig(HTCFG_LEDC_SEG7_GPIO_ID, HTCFG_LEDC_SEG7_AFIO_PIN, AFIO_FUN_LEDC);
/* COM0~4 */
AFIO_GPxConfig(HTCFG_LEDC_COM0_GPIO_ID, HTCFG_LEDC_COM0_AFIO_PIN, AFIO_FUN_LEDC);
AFIO_GPxConfig(HTCFG_LEDC_COM1_GPIO_ID, HTCFG_LEDC_COM1_AFIO_PIN, AFIO_FUN_LEDC);
AFIO_GPxConfig(HTCFG_LEDC_COM2_GPIO_ID, HTCFG_LEDC_COM2_AFIO_PIN, AFIO_FUN_LEDC);
AFIO_GPxConfig(HTCFG_LEDC_COM3_GPIO_ID, HTCFG_LEDC_COM3_AFIO_PIN, AFIO_FUN_LEDC);
}
{
LEDC_InitTypeDef LEDC_InitStruct;
/* Turn on the APB clock of LEDC. */
CKCU_PeripClockConfig_TypeDef CKCUClock = {{0}};
CKCUClock.Bit.LEDC = 1;
CKCU_PeripClockConfig(CKCUClock, ENABLE);
/* Frame = fCK_LED / (LEDC_DutyClockNumber * COM Number) */
/* = 1600 / (8*4) = 50Hz */
LEDC_InitStruct.LEDC_ClockSource = LEDC_SRC_LSI; /* LSI = 32Khz */
LEDC_InitStruct.LEDC_ClockPrescaler = HTCFG_LEDC_CLOCK_PRESCAL - 1; /* fCK_LED = 32Khz / 20 = 1600 Hz */
LEDC_InitStruct.LEDC_DutyClockNumber = HTCFG_LEDC_DUTY_CLOCK_NUMBER; /* Duty CLock Number = 8 Clock */
LEDC_InitStruct.LEDC_COMxEN = HTCFG_LEDC_COM1EN | HTCFG_LEDC_COM2EN |\
HTCFG_LEDC_COM3EN | HTCFG_LEDC_COM4EN; /* Enable COMx */
/* Change the brightness, the parameter range is 0~Duty (CLock Number-1.) */
/* 0: the brightest, 7: the darkest. */
LEDC_InitStruct.LEDC_DeadTime = 0;
LEDC_Init(&LEDC_InitStruct); /* LEC initialization. */
/* Set the LEDC mode to COMMON_CATHODE. */
LEDC_SetPolarityMode(HTCFG_LEDC_COM1POL | HTCFG_LEDC_COM2POL | HTCFG_LEDC_COM3POL | HTCFG_LEDC_COM4POL,
LEDC_SEG0POL | LEDC_SEG1POL | LEDC_SEG2POL | LEDC_SEG3POL |\
LEDC_SEG4POL | LEDC_SEG5POL | LEDC_SEG6POL | LEDC_SEG7POL,
COMMON_CATHODE);
//LEDC_IntConfig(ENABLE); /* Enable frame interrupt. */
//NVIC_EnableIRQ(LEDC_IRQn); /* Enable LECD IRQ. */
LEDC_Cmd(ENABLE); /* LEDC Start. */
}
}
void bsp_ledc_display(u16 val)
{
LEDC_SetData(HTCFG_LEDC_COM_D1, NumberChar[val/1000%10]);
LEDC_SetData(HTCFG_LEDC_COM_D2, NumberChar[val/100%10]);
LEDC_SetData(HTCFG_LEDC_COM_D3, NumberChar[val/10%10]);
LEDC_SetData(HTCFG_LEDC_COM_D4, NumberChar[val%10]);
}
使用systick产生1ms定时中断,作为软件定时器的基准。
{
/* SYSTICK configuration */
SYSTICK_ClockSourceConfig(SYSTICK_SRC_STCLK); // Default : CK_AHB/8
SYSTICK_SetReloadValue(SystemCoreClock / 8 / 1000); // (CK_AHB/8/1000) = 1ms on chip
SYSTICK_IntConfig(ENABLE); // Enable SYSTICK Interrupt
SYSTICK_CounterCmd(SYSTICK_COUNTER_ENABLE);
}
定义软件定时器,(此处代码参考安富莱例程)。
//bsp_stimer.h
#ifndef __BSP_STIMER_H
#define __BSP_STIMER_H
#define TMR_COUNT 2 /* 软件定时器的个数 (定时器ID范围 0 - 3) */
#define TMR_REFRESH_DISPLAY 0 //用户更新数码管显示
#define TMR_ADC_SAMPLE 1 //用于ADC滤波,计算转换结果
typedef enum
{
TMR_MODE_ONCE = 0, /* 一次工作模式 */
TMR_MODE_AUTO = 1, /* 自动定时工作模式 */
TMR_MODE_STOP = 2,
}tmr_mode_t;
typedef struct
{
volatile u8 Mode; /* 计数器模式,1次性 */
volatile u8 Flag; /* 定时到达标志 */
volatile u32 Count; /* 计数器 */
volatile u32 PreLoad; /* 计数器预装值 */
}soft_tmr_t;
void bsp_stimer_init(void);
void bsp_stimer_start(u8 _id, u32 _period, tmr_mode_t mode);
void bsp_stimer_stop(u8 _id);
u8 bsp_stimer_check(u8 _id);
void bsp_stimer_dec(void);
#endif
// bsp_stimer.c
#include "ht32.h"
#include "bsp_stimer.h"
/* 定于软件定时器结构体变量 */
static soft_tmr_t s_tTmr[TMR_COUNT] = {0};
/*
*********************************************************************************************************
* 函 数 名: bsp_stimer_init
* 功能说明: 配置systick中断,并初始化软件定时器变量
* 形 参: 无
* 返 回 值: 无
*********************************************************************************************************
*/
void bsp_stimer_init(void)
{
/* SYSTICK configuration */
SYSTICK_ClockSourceConfig(SYSTICK_SRC_STCLK); // Default : CK_AHB/8
SYSTICK_SetReloadValue(SystemCoreClock / 8 / 1000); // (CK_AHB/8/1000) = 1ms on chip
SYSTICK_IntConfig(ENABLE); // Enable SYSTICK Interrupt
SYSTICK_CounterCmd(SYSTICK_COUNTER_ENABLE);
}
/*
*********************************************************************************************************
* 函 数 名: bsp_stimer_init
* 功能说明: 每隔1ms对所有定时器变量减1。必须被SysTick_Handler中断函数周期性调用。
* 形 参:
* 返 回 值: 无
*********************************************************************************************************
*/
void bsp_stimer_dec(void)
{
u8 i;
for (i = 0; i < TMR_COUNT; i++)
{
if(s_tTmr[i].Mode != TMR_MODE_STOP)
{
if (s_tTmr[i].Count > 0)
{
if (--s_tTmr[i].Count == 0)
{
s_tTmr[i].Flag = 1;
if(s_tTmr[i].Mode == TMR_MODE_AUTO)
{
s_tTmr[i].Count = s_tTmr[i].PreLoad;
}
}
}
}
}
}
/*
*********************************************************************************************************
* 函 数 名: bsp_stimer_start
* 功能说明: 启动一个定时器,并设置定时周期。
* 形 参: _id : 定时器ID,值域【0,TMR_COUNT-1】。用户必须自行维护定时器ID,以避免定时器ID冲突。
* _period : 定时周期,单位1ms
* _mode : 定时器工作模式,一次性、连续
* 返 回 值: 无
*********************************************************************************************************
*/
void bsp_stimer_start(u8 _id, u32 _period, tmr_mode_t _mode)
{
if (_id >= TMR_COUNT)
{
while(1); /* 参数异常,死机等待看门狗复位 */
}
__disable_irq(); /* 关中断 */
s_tTmr[_id].Count = _period; /* 实时计数器初值 */
s_tTmr[_id].PreLoad = _period; /* 计数器自动重装值,仅自动模式起作用 */
s_tTmr[_id].Flag = 0; /* 定时时间到标志 */
s_tTmr[_id].Mode = _mode; /* 工作模式 */
__enable_irq(); /* 开中断 */
}
/*
*********************************************************************************************************
* 函 数 名: bsp_stimer_stop
* 功能说明: 停止一个定时器
* 形 参: _id : 定时器ID,值域【0,TMR_COUNT-1】。用户必须自行维护定时器ID,以避免定时器ID冲突。
* 返 回 值: 无
*********************************************************************************************************
*/
void bsp_stimer_stop(u8 _id)
{
if (_id >= TMR_COUNT)
{
while(1); /* 参数异常,死机等待看门狗复位 */
}
__disable_irq(); /* 关中断 */
s_tTmr[_id].Count = 0; /* 实时计数器初值 */
s_tTmr[_id].Flag = 0; /* 定时时间到标志 */
s_tTmr[_id].Mode = TMR_MODE_STOP; /* 自动工作模式 */
__enable_irq(); /* 开中断 */
}
/*
*********************************************************************************************************
* 函 数 名: bsp_stimer_check
* 功能说明: 检测定时器是否超时
* 形 参: _id : 定时器ID,值域【0,TMR_COUNT-1】。用户必须自行维护定时器ID,以避免定时器ID冲突。
* _period : 定时周期,单位1ms
* 返 回 值: 返回 0 表示定时未到, 1表示定时到
*********************************************************************************************************
*/
u8 bsp_stimer_check(u8 _id)
{
if (_id >= TMR_COUNT)
{
return 0;
}
if (s_tTmr[_id].Flag == 1)
{
s_tTmr[_id].Flag = 0; return 1;
}
else
{
return 0;
}
}
好的,到此各个模块已经准备好了,在main函数中调用这几个模块就可以显示出想要的结果。
int main(void)
{
bsp_stimer_init();
bsp_adc_sample();
bsp_ledc_config();
bsp_ledc_display(8888);
HT32F_DVB_LEDInit(HT_LED1);
bsp_stimer_start(TMR_REFRESH_DISPLAY, 1000, TMR_MODE_AUTO);
bsp_stimer_start(TMR_ADC_SAMPLE, 50, TMR_MODE_AUTO);
while (1)
{
if(bsp_stimer_check(TMR_ADC_SAMPLE))
{
bsp_adc_chache();
}
if(bsp_stimer_check(TMR_REFRESH_DISPLAY))
{
u16 adc_val;
adc_val = get_adc_value();
bsp_ledc_display(adc_val);
HT32F_DVB_LEDToggle(HT_LED1);
}
}
}
左右旋转Potentiometer电位器,在数码管上就会显示出当前ADC转换值。
|
此文章已获得独家原创/原创奖标签,著作权归21ic所有,未经允许禁止转载。
共2人点赞
|