GD32F4XX的配置和函数归纳(4)
1.分析了ADC的例程,看看其中的配置是如何实现的
目录
1.ADC 温度传感器
#include "gd32f4xx.h"
#include "gd32f450z_eval.h"
#include "systick.h"
#include <stdio.h>
float temperature;
float vref_value;
float battery_value;
void rcu_config(void);
void adc_config(void);
int main(void)
{
/* system clocks configuration */
rcu_config();
/* ADC configuration */
adc_config();
/* USART configuration */
gd_eval_com_init(EVAL_COM0);
/* configure systick */
systick_config();
while(1){
/* ADC software trigger enable */
adc_software_trigger_enable(ADC0,ADC_INSERTED_CHANNEL);
/* delay a time in milliseconds */
delay_1ms(2000);
/* value convert */
temperature = (1.42-ADC_IDATA0(ADC0)*3.3/4096)*1000/4.35+25;
vref_value = (ADC_IDATA1(ADC0)*3.3/4096);
battery_value = (ADC_IDATA2(ADC0)*4*3.3/4096);
/* value print */
printf(" the temperature data is %2.0f degrees Celsius\r\n",temperature);
printf(" the reference voltage data is %5.3fV \r\n",vref_value);
printf(" the battery voltage is %5.3fV \r\n",battery_value);
printf(" \r\n");
}
}
1.1 RCU配置
RCU的配置,使能外设时钟函数rcu_periph_clock_enable(),这个函数是将输入的外设时钟给打开。
ADC时钟的配置adc_clock_config(),配置adc的时钟,一个有八种分频方式,调用两种时钟源
这是常用的两个配置语句,给出官方备注以便后面使用
void rcu_config(void)
{
/* enable ADC clock */
rcu_periph_clock_enable(RCU_ADC0);
/* config ADC clock */
adc_clock_config(ADC_ADCCK_PCLK2_DIV4);
}
/*!
\brief enable the peripherals clock
\param[in] periph: RCU peripherals, refer to rcu_periph_enum
only one parameter can be selected which is shown as below:
\arg RCU_GPIOx (x=A,B,C,D,E,F,G,H,I): GPIO ports clock
\arg RCU_CRC: CRC clock
\arg RCU_BKPSRAM: BKPSRAM clock
\arg RCU_TCMSRAM: TCMSRAM clock
\arg RCU_DMAx (x=0,1): DMA clock
\arg RCU_IPA: IPA clock
\arg RCU_ENET: ENET clock
\arg RCU_ENETTX: ENETTX clock
\arg RCU_ENETRX: ENETRX clock
\arg RCU_ENETPTP: ENETPTP clock
\arg RCU_USBHS: USBHS clock
\arg RCU_USBHSULPI: USBHSULPI clock
\arg RCU_DCI: DCI clock
\arg RCU_TRNG: TRNG clock
\arg RCU_USBFS: USBFS clock
\arg RCU_EXMC: EXMC clock
\arg RCU_TIMERx (x=0,1,2,3,4,5,6,7,8,9,10,11,12,13): TIMER clock
\arg RCU_WWDGT: WWDGT clock
\arg RCU_SPIx (x=0,1,2,3,4,5): SPI clock
\arg RCU_USARTx (x=0,1,2,5): USART clock
\arg RCU_UARTx (x=3,4,6,7): UART clock
\arg RCU_I2Cx (x=0,1,2): I2C clock
\arg RCU_CANx (x=0,1): CAN clock
\arg RCU_PMU: PMU clock
\arg RCU_DAC: DAC clock
\arg RCU_RTC: RTC clock
\arg RCU_ADCx (x=0,1,2): ADC clock
\arg RCU_SDIO: SDIO clock
\arg RCU_SYSCFG: SYSCFG clock
\arg RCU_TLI: TLI clock
\arg RCU_CTC: CTC clock
\arg RCU_IREF: IREF clock
\param[out] none
\retval none
*/
/*!
\brief configure the ADC clock for all the ADCs
\param[in] prescaler: configure ADCs prescaler ratio
only one parameter can be selected which is shown as below:
\arg ADC_ADCCK_PCLK2_DIV2: PCLK2 div2
\arg ADC_ADCCK_PCLK2_DIV4: PCLK2 div4
\arg ADC_ADCCK_PCLK2_DIV6: PCLK2 div6
\arg ADC_ADCCK_PCLK2_DIV8: PCLK2 div8
\arg ADC_ADCCK_HCLK_DIV5: HCLK div5
\arg ADC_ADCCK_HCLK_DIV6: HCLK div6
\arg ADC_ADCCK_HCLK_DIV10: HCLK div10
\arg ADC_ADCCK_HCLK_DIV20: HCLK div20
\param[out] none
\retval none
*/
1.2 ADC配置
这里调用了很多adc.c和adc.h的变量和函数,总体配置思路如下:
1.先将ADC0配置成注入通道,采样率设置为3
2.配置三个内部传感器(温度传感器,内部参考电压 VREFINT和外部电池电压 VBAT)的采样率
3.关闭外部触发源
4.设置数据对齐方式为右对齐
5.将ADC0转换模式调为扫描模式
6.使能三个内部传感器
7.使能ADC0
8.校准三个内部传感器
void adc_config(void)
{
/* ADC channel length config */
adc_channel_length_config(ADC0,ADC_INSERTED_CHANNEL,3);
/* ADC temperature sensor channel config */
adc_inserted_channel_config(ADC0,0,ADC_CHANNEL_16,ADC_SAMPLETIME_480);
/* ADC internal reference voltage channel config */
adc_inserted_channel_config(ADC0,1,ADC_CHANNEL_17,ADC_SAMPLETIME_480);
/* ADC 1/4 voltate of external battery config */
adc_inserted_channel_config(ADC0,2,ADC_CHANNEL_18,ADC_SAMPLETIME_480);
/* ADC external trigger enable */
adc_external_trigger_config(ADC0,ADC_INSERTED_CHANNEL,DISABLE);
/* ADC data alignment config */
adc_data_alignment_config(ADC0,ADC_DATAALIGN_RIGHT);
/* ADC SCAN function enable */
adc_special_function_config(ADC0,ADC_SCAN_MODE,ENABLE);
/* ADC Vbat channel enable */
adc_channel_16_to_18(ADC_VBAT_CHANNEL_SWITCH,ENABLE);
/* ADC temperature and Vrefint enable */
adc_channel_16_to_18(ADC_TEMP_VREF_CHANNEL_SWITCH,ENABLE);
/* enable ADC interface */
adc_enable(ADC0);
/* ADC calibration and reset calibration */
adc_calibration_enable(ADC0);
}
1.3 com口初始化配置
com端口配置是以下函数,主要步骤是:使能串口控制器,再将端口连接到串口控制器的读写端,再将读写设置成推挽模式,最后将串口控制器配置完成即可。
gd_eval_com_init(uint32_t com)
1.4 系统配置
系统配置函数内有两部:建立1000hz的系统时钟和将其配置为最强的中断优先级。
systick_config();
2. ADC0 和 ADC1 跟随模式
与上面不同的是:
1.TIMER1_CH1 作为 ADC0 和 ADC1 的触发源,而上个例程是直接调用
2.ADC0 和 ADC1 的值通过 DMA 传送给 adc_value[0]和 adc_value[1],使用两个ADC,并且采用规则通道(规则通道相比注入通道而言,是一直进行的而不需要中断重新进入)
得到adc_value[0]和 adc_value[1]值后,根据TIMER上升沿,更新数据。
int main(void)
{
/* system clocks configuration */
rcu_config();
/* GPIO configuration */
gpio_config();
/* TIMER configuration */
timer_config();
/* DMA configuration */
dma_config();
/* ADC configuration */
adc_config();
/* configure COM port */
gd_eval_com_init(EVAL_COM0);
/* configure systick */
systick_config();
while(1){
delay_1ms(2000);
printf(" the data adc_value[0] is %08X \r\n",adc_value[0]);
printf(" the data adc_value[1] is %08X \r\n",adc_value[1]);
printf("\r\n");
}
}
2.1 dma配置
它的主要思路是,先初始化所需要的dma1的第一个通道(该芯片一共2个dma,每个有8通道);再依次配置dma.c中设置好的结构体变量
配置好结构体变量后,再将结构体的参数配置到dma1的第一个通道,用下面函数,最后一步是使能该通道。
dma_single_data_mode_init(DMA1,DMA_CH0,DMA_SUBPERI0)
void dma_config(void)
{
/* ADC_DMA_channel configuration */
dma_single_data_parameter_struct dma_single_data_parameter;
/* ADC_DMA_channel deinit */
dma_deinit(DMA1,DMA_CH0);
/* initialize DMA single data mode */
dma_single_data_parameter.periph_addr = (uint32_t)(&ADC_SYNCDATA);
dma_single_data_parameter.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
dma_single_data_parameter.memory0_addr = (uint32_t)(adc_value);
dma_single_data_parameter.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
dma_single_data_parameter.periph_memory_width = DMA_PERIPH_WIDTH_32BIT;
dma_single_data_parameter.circular_mode = DMA_CIRCULAR_MODE_ENABLE;
dma_single_data_parameter.direction = DMA_PERIPH_TO_MEMORY;
dma_single_data_parameter.number = 2;
dma_single_data_parameter.priority = DMA_PRIORITY_HIGH;
dma_single_data_mode_init(DMA1,DMA_CH0,&dma_single_data_parameter);
/* DMA channel 0 peripheral select */
dma_channel_subperipheral_select(DMA1,DMA_CH0,DMA_SUBPERI0);
/* enable DMA channel */
dma_channel_enable(DMA1,DMA_CH0);
}
2.2 ADC0/1规则通道下的配置
第一个函数是将其ADC0/1设置为跟随模式:
后面再将ADC0/1设置为右对齐和扫描模式,配置为规则通道,设置采样率,再分别将ADC0/1进行使能和校准。与上例子不同的是,这里采用timer 0 cc1作为触发源。
void adc_config(void)
{
/* configure the ADC sync mode */
adc_sync_mode_config(ADC_DAUL_REGULAL_FOLLOW_UP);
adc_sync_dma_config(ADC_SYNC_DMA_MODE1); //模式1
adc_sync_dma_request_after_last_enable(); //dma使用完就禁用
/* ADC data alignment config */
adc_data_alignment_config(ADC0,ADC_DATAALIGN_RIGHT);
adc_data_alignment_config(ADC1,ADC_DATAALIGN_RIGHT);
/* ADC scan mode function enable */
adc_special_function_config(ADC0,ADC_SCAN_MODE,ENABLE);
adc_special_function_config(ADC1,ADC_SCAN_MODE,ENABLE);
/* ADC channel length config */
adc_channel_length_config(ADC0,ADC_REGULAR_CHANNEL,2);
adc_channel_length_config(ADC1,ADC_REGULAR_CHANNEL,2);
/* ADC regular channel config */
adc_regular_channel_config(ADC0,0,ADC_CHANNEL_13,ADC_SAMPLETIME_480);
adc_regular_channel_config(ADC0,1,ADC_CHANNEL_15,ADC_SAMPLETIME_480);
adc_regular_channel_config(ADC1,1,ADC_CHANNEL_13,ADC_SAMPLETIME_480);
adc_regular_channel_config(ADC1,0,ADC_CHANNEL_15,ADC_SAMPLETIME_480);
/* ADC external trigger enable */
adc_external_trigger_config(ADC0,ADC_REGULAR_CHANNEL,EXTERNAL_TRIGGER_RISING);
adc_external_trigger_config(ADC1,ADC_REGULAR_CHANNEL,EXTERNAL_TRIGGER_DISABLE);
adc_external_trigger_source_config(ADC0,ADC_REGULAR_CHANNEL,ADC_EXTTRIG_REGULAR_T1_CH1);
/* enable ADC interface */
adc_enable(ADC0);
/* ADC calibration and reset calibration */
adc_calibration_enable(ADC0);
/* enable ADC interface */
adc_enable(ADC1);
/* ADC calibration and reset calibration */
adc_calibration_enable(ADC1);
}
2.3 TIMER配置
先设置初始外设和输出外设的结构体参数
再设置PWM的模式
void timer_config(void)
{
timer_oc_parameter_struct timer_ocintpara;
timer_parameter_struct timer_initpara;
/* TIMER1 configuration */
timer_initpara.prescaler = 19999;
timer_initpara.alignedmode = TIMER_COUNTER_EDGE;
timer_initpara.counterdirection = TIMER_COUNTER_UP;
timer_initpara.period = 9999;
timer_initpara.clockdivision = TIMER_CKDIV_DIV1;
timer_initpara.repetitioncounter = 0;
timer_init(TIMER1,&timer_initpara);
/* CH1 configuration in PWM mode0 */
timer_ocintpara.ocpolarity = TIMER_OC_POLARITY_HIGH;
timer_ocintpara.ocnpolarity = TIMER_OCN_POLARITY_HIGH;
timer_ocintpara.outputnstate = TIMER_CCXN_DISABLE;
timer_ocintpara.outputstate = TIMER_CCX_ENABLE;
timer_ocintpara.ocidlestate = TIMER_OC_IDLE_STATE_LOW;
timer_ocintpara.ocnidlestate = TIMER_OCN_IDLE_STATE_LOW;
timer_channel_output_config(TIMER1,TIMER_CH_1,&timer_ocintpara);
timer_channel_output_pulse_value_config(TIMER1,TIMER_CH_1,3999);
timer_channel_output_mode_config(TIMER1,TIMER_CH_1,TIMER_OC_MODE_PWM0);
timer_channel_output_shadow_config(TIMER1,TIMER_CH_1,TIMER_OC_SHADOW_DISABLE);
/* enable TIMER1 */
timer_enable(TIMER1);
}
3. ADC0和ADC1规则并行模式
只需要将上个例程ADC配置的跟随模式改为规则模式即可:
/* ADC channel length config */
adc_channel_length_config(ADC0,ADC_REGULAR_CHANNEL,2);
adc_channel_length_config(ADC1,ADC_REGULAR_CHANNEL,2);