涉及到的硬件需求:
一、硬件资源
1、使用外部设备驱动ADC——选用ADC2
ADC框架
2、在使用ADC2,查看哪个timer可以触发ADC,通过下图可以看到timer4通道0可以驱动ADC
2、在使用ADC2,看一下哪个,DMA可以搬运数据,进入用户手册的DMA章节看资源
二、程序部分
0、头文件
#ifndef __BSP_ADC_H__
#define __BSP_ADC_H__
#include "gd32f30x.h"
#include "para_flag.h"
#include "gd32f30x_timer.h"
#include "gd32f30x_dma.h"
#define LASWER_FRE_NUME 1024
#define ADC_CHANNEL_NUMER 2
//PWM
#define ADC_PWM_TMER_RCU RCU_TIMER4
#define ADC_PWM_TMER TIMER4
#define ADC_PWM_CH TIMER_CH_0
//ADC
#define ADC_NUM_CH ADC2
#define ADC_RCU RCU_ADC2
#define ADC_EXTTRIG_CH ADC2_EXTTRIG_REGULAR_T4_CH0
void App_AdcSglCfg(wavelength_battery value);
void ADC_init(void);
uint16_t ADC_meas(void);
uint16_t filter_motor (uint16_t barray[LASWER_FRE_NUME][ADC_CHANNEL_NUMER],uint8_t ifilterlen);
#endif // __SW74HC4051_H__
1、时钟函数配置
/*!
\brief configure the different system clocks
\param[in] none
\param[out] none
\retval none
*/
static void rcu_config(void)
{
/* enable GPIOA clock */
rcu_periph_clock_enable(RCU_GPIOA);
/* enable DMA clock */
rcu_periph_clock_enable(RCU_DMA1);
/* enable TIMER0 clock */
rcu_periph_clock_enable(ADC_PWM_TMER_RCU);
/* enable ADC2 clock */
rcu_periph_clock_enable(ADC_RCU);
/* config ADC clock */
rcu_adc_clock_config(RCU_CKADC_CKAPB2_DIV6);
}
2、定时器配置
//Timer4配置初始化
void App_Timer4Cfg(void)
{
/* TIMER0 配置:产生不同占空比的 PWM 信号:
TIMER0CLK = SystemCoreClock / 120 = 1MHz */
timer_parameter_struct timer_initpara;
timer_oc_parameter_struct timer_ocintpara;
rcu_periph_clock_enable(ADC_PWM_TMER_RCU); //开启定时器时钟
timer_deinit(ADC_PWM_TMER); //取消定时器
/* TIMERX 配置 */
timer_initpara.prescaler = 11999;
timer_initpara.alignedmode = TIMER_COUNTER_EDGE;
timer_initpara.counterdirection = TIMER_COUNTER_UP; //向上计数
timer_initpara.period = 100-1;
timer_initpara.clockdivision = TIMER_CKDIV_DIV1;
timer_initpara.repetitioncounter = 0;
timer_init(ADC_PWM_TMER,&timer_initpara);
/* CHX configuration in PWM mode0 */
timer_channel_output_struct_para_init(&timer_ocintpara);
timer_ocintpara.ocpolarity = TIMER_OC_POLARITY_HIGH;
timer_ocintpara.outputstate = TIMER_CCX_ENABLE;
timer_channel_output_config(ADC_PWM_TMER,ADC_PWM_CH,&timer_ocintpara);
timer_channel_output_pulse_value_config(ADC_PWM_TMER, ADC_PWM_CH, 50);
timer_channel_output_mode_config(ADC_PWM_TMER, ADC_PWM_CH, TIMER_OC_MODE_PWM0);
timer_channel_output_shadow_config(ADC_PWM_TMER, ADC_PWM_CH, TIMER_OC_SHADOW_DISABLE);
/* auto-reload preload enable */
timer_auto_reload_shadow_enable(ADC_PWM_TMER);
}
3、DMA配置
/*!
\brief 直接存储器存取配置功能
\param[in] none
\param[out] none
\retval none
*/
void dma_config(void)
{
/* enable DMA clock */
// rcu_periph_clock_enable(RCU_DMA);
dma_parameter_struct dma_init_struct;
/* 初始化DMA channel0 */
dma_deinit(DMA1, DMA_CH4);
dma_init_struct.direction = DMA_PERIPHERAL_TO_MEMORY; /*!< 从外设读取并写入内存 */
dma_init_struct.memory_addr = (uint32_t)laser_fre; //目标地址
dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE; /*!< 内存的下一个地址是递增地址模式 */
dma_init_struct.memory_width = DMA_MEMORY_WIDTH_16BIT; /*!< 传输数据的内存大小为16位 */
dma_init_struct.number = LASWER_FRE_NUME*ADC_CHANNEL_NUMER; //传输的个数
dma_init_struct.periph_addr = (uint32_t)(&ADC_RDATA(ADC_NUM_CH)); //源地址
dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE; /*!< 外设的下一个地址为固定地址模式 */
dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_16BIT; /*!< 外设传输数据大小为16位 */
dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH; /*!< 超高的优先级 */
dma_init(DMA1, DMA_CH4, &dma_init_struct);
/* 配置DMA模式 */
dma_circulation_enable(DMA1, DMA_CH4);
//中断配置
nvic_irq_enable(DMA1_Channel3_Channel4_IRQn,0,1);
dma_interrupt_enable(DMA1,DMA_CH4,DMA_INT_FTF);
/* 支持DMA channel0*/
dma_channel_enable(DMA1, DMA_CH4);
}
4、ADC配置
//-------------------------------------------------------------------------------
//函数名:App_AdcInit
//输 入:void
//输 出:void
//功 能:ADC 模块初始化,ADCCLK =4MHz,4MHz/28 = 142.8kHz
//-----------------------------------------------------------------------------
void App_AdcInit(void)
{
adc_deinit(ADC_NUM_CH);
/* 开启ADC扫描模式功能 */
adc_special_function_config(ADC_NUM_CH, ADC_SCAN_MODE, ENABLE);
/* ADC通道数量配置 */
adc_channel_length_config(ADC_NUM_CH,ADC_REGULAR_CHANNEL, 2);
/* ADC常规通道配置 */
adc_regular_channel_config(ADC_NUM_CH,0, ADC_CHANNEL_0, ADC_SAMPLETIME_55POINT5);
adc_regular_channel_config(ADC_NUM_CH,1, ADC_CHANNEL_1, ADC_SAMPLETIME_55POINT5);
// adc_regular_channel_config(ADC_NUM_CH,2, ADC_CHANNEL_2, ADC_SAMPLETIME_55POINT5);
/* ADC外部触发启用 */
adc_external_trigger_config(ADC_NUM_CH,ADC_REGULAR_CHANNEL, ENABLE);
/* ADC外部触发源配置 */
adc_external_trigger_source_config(ADC_NUM_CH,ADC_REGULAR_CHANNEL, ADC_EXTTRIG_CH);
//注入组
// adc_channel_length_config(ADC_INSERTED_CHANNEL, 1);
// adc_inserted_channel_config(0, ADC_CHANNEL_2, ADC_SAMPLETIME_55POINT5);
// adc_external_trigger_source_config(ADC_INSERTED_CHANNEL, ADC_EXTTRIG_INSERTED_T14_TRGO);
// adc_external_trigger_config(ADC_INSERTED_CHANNEL, ENABLE);
adc_resolution_config(ADC_NUM_CH,ADC_RESOLUTION_12B);
/* ADC数据对齐配置 */
adc_data_alignment_config(ADC_NUM_CH,ADC_DATAALIGN_RIGHT);
/* 启用ADC接口 */
adc_enable(ADC_NUM_CH);
/* ADC校准和复位校准 */
adc_calibration_enable(ADC_NUM_CH);
/* ADC DMA功能使能 */
adc_dma_mode_enable(ADC_NUM_CH);
}
5、端口配置
/*
*********************************************************************************************************
* 函 数 名: void App_datacollection_PORT_init(void)
* 功能说明: 数据采集端口配置
* 形 参: 无
* 返 回 值: 无
*********************************************************************************************************
*/
void App_datacollection_PORT_init(void)
{
/*configure PA8(TIMER0 CH0) as alternate function*/
gpio_init(GPIOA, GPIO_MODE_AIN, GPIO_OSPEED_MAX, GPIO_PIN_1);
gpio_init(GPIOA, GPIO_MODE_AIN, GPIO_OSPEED_MAX, GPIO_PIN_0);
}
6、ADC全部初始化
//ADC初始化
void ADC_init(void)
{
rcu_config();
App_datacollection_PORT_init();//端口初始化
App_Timer4Cfg();
dma_config();
App_AdcInit();//模块初始化
timer_enable(ADC_PWM_TMER);
}
7、滤波函数
//-------------------------------------------------------------------------------
//函数名:filter_bat
//输 入:time 延时循环的次数
//输 出:void
//功 能:中位值平均滤波法
//-----------------------------------------------------------------------------
uint16_t filter_bat (uint16_t barray[LASWER_FRE_NUME][ADC_CHANNEL_NUMER],uint8_t ifilterlen)
{
unsigned char i,j;
uint16_t btemp = 0;
uint16_t sum = 0;
//用冒泡法对数组进行排序
for (j = FILER_MID; j < ifilterlen-1+FILER_MID; ++j)
{
for (i = FILER_MID; i < ifilterlen-1+FILER_MID; ++i)
{
if (barray[i][0]>barray[i+1][0])
{
btemp =barray[i][0];
barray[i][0]=barray[i+1][0];
barray[i+1][0]=btemp;
}
}
}
//累加
for(i = 3+FILER_MID;i< ifilterlen-3+FILER_MID;i++)
{
sum =sum + barray[i][0];
}
return (sum>>2);
}
8、DMA中断服务函数
//当传输完成足够的数据后,就关闭定时器,设置标志位,进行处理,可以在中断中处理,
void DMA1_Channel3_4_IRQHandler(void)
{
//传输完成标志位
if(dma_interrupt_flag_get(DMA1,DMA_CH4, DMA_INT_FLAG_FTF))
{
//关闭定时器,停止继续读取数据
timer_channel_output_mode_config(ADC_PWM_TMER, ADC_PWM_CH, TIMER_OC_MODE_HIGH);
//清除全部标志位
dma_interrupt_flag_clear(DMA1,DMA_CH4, DMA_INT_FLAG_G);
//设置标志位 DMA完成了
Lcd_flag.battery_adc_flag = true;
}
}
9、数据采集
/*
*********************************************************************************************************
* 函 数 名: ADC_meas
* 功能说明: 电池电量ADC采集
* 形 参: 无
* 返 回 值: 无
*********************************************************************************************************
*/
uint16_t ADC_meas(void)
{
unsigned int j,ad_data = 0;
static bool adc_init_flag = false ;
static uint16_t adc_battery_data = 0;
//返回数据
if (Lcd_flag.battery_adc_flag == true)
{
adc_battery_data = filter_bat(laser_fre, 10);
}
//采集数据
if (Lcd_flag.battery_adc_flag ==true || adc_init_flag == false)
{
Lcd_flag.battery_adc_flag = false;
adc_init_flag = true;
timer_channel_output_mode_config(ADC_PWM_TMER, ADC_PWM_CH, TIMER_OC_MODE_PWM1);
}
return adc_battery_data;
}
目录
2、在使用ADC2,查看哪个timer可以触发ADC,通过下图可以看到timer4通道0可以驱动ADC
2、在使用ADC2,看一下哪个,DMA可以搬运数据,进入用户手册的DMA章节看资源