stm32和同类单片机用ADC采集多通道信号量
2024-10-08 来源:cnblogs
在此之前,使用stm32的ADC采集信号,使用到的通道就只有一个,用的时候也是别人写好的代码,没去研究,然而最近用GD32F350单片机作一个电源板时,要采集6个通道的信号,所以就仔细看了手册,有规则通道和注入通道两个概念,按概念,规则通道是按顺序采集,注入通道可以最多设备四个,有独立的保存采集数据的寄存器。如果超过4个就不能没每个每个通道对应一个数据寄存器;如果是规则通道,当通道数大于一时是可以先设置采集通道再读数据,但是我想要的是像手册上说大的一次就把6个通道的数据采集出来,但是规则通道只有一个数据寄存器,如何知道每一次采集的数据是对应哪一个通道呢?最后问了一个做电源有经验的人,他说使用DMA,设置数据长度为6个,然后每个通道采集的的数据就按顺序存到指定的地址了,真是一语惊醒梦中人啊。看看代码吧:
void dma_config(void)
{
dma_parameter_struct dma_init_struct;
rcu_periph_clock_enable(RCU_DMA);
/* initialize DMA channel0 */
dma_deinit(DMA_CH0);
dma_init_struct.direction = DMA_PERIPHERAL_TO_MEMORY;
dma_init_struct.memory_addr = (uint32_t)ad_value;//指定DMA数据空间地址
dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
dma_init_struct.memory_width = DMA_MEMORY_WIDTH_16BIT;
dma_init_struct.number = 48;
dma_init_struct.periph_addr = (uint32_t)&(ADC_RDATA);
dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_16BIT;
dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;
dma_init(DMA_CH0, dma_init_struct);
/* configure DMA mode */
dma_circulation_enable(DMA_CH0);
dma_memory_to_memory_disable(DMA_CH0);
/* enable DMA channel0 */
dma_channel_enable(DMA_CH0);
dma_interrupt_enable(DMA_CH0, DMA_INT_FTF);
nvic_irq_enable(DMA_Channel0_IRQn , 0U, 0U);//配置中断优先级
}
void ADCSampleInit(void)
{
// rcu_periph_clock_enable(RCU_GPIOB);
// gpio_mode_set(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_15);
// gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_15);
dma_config();
// ADCCLK = PCLK2/6
rcu_adc_clock_config(RCU_ADCCK_APB2_DIV4);// ADC时钟27MHz
rcu_periph_clock_enable(RCU_ADC);
rcu_periph_clock_enable(RCU_GPIOA);
//PA2,3,4,5,6
gpio_mode_set(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE,
GPIO_PIN_2|GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6);
// ADC channel length config 设置规则组的数量,转换扫描时按此数量扫描
adc_channel_length_config(ADC_REGULAR_CHANNEL, 6);
/* ADC regular channel config */
adc_regular_channel_config(0, ADC_CHANNEL_2, ADC_SAMPLETIME_1POINT5);
adc_regular_channel_config(1, ADC_CHANNEL_3, ADC_SAMPLETIME_1POINT5);
adc_regular_channel_config(2, ADC_CHANNEL_4, ADC_SAMPLETIME_1POINT5);
adc_regular_channel_config(3, ADC_CHANNEL_5, ADC_SAMPLETIME_1POINT5);
adc_regular_channel_config(4, ADC_CHANNEL_6, ADC_SAMPLETIME_1POINT5);
//Vrefin
adc_regular_channel_config(5, ADC_CHANNEL_17, ADC_SAMPLETIME_13POINT5);//ADC_SAMPLETIME_13POINT5 1515 //ADC_SAMPLETIME_28POINT5 1462
//adc_regular_channel_config(5, ADC_CHANNEL_16, ADC_SAMPLETIME_13POINT5);
// Vrefin enable
adc_tempsensor_vrefint_enable();
/* ADC external trigger enable */
adc_external_trigger_config(ADC_REGULAR_CHANNEL, ENABLE);
/* ADC external trigger source config */
adc_external_trigger_source_config(ADC_REGULAR_CHANNEL, ADC_EXTTRIG_REGULAR_NONE);
/* ADC data alignment config */
adc_data_alignment_config(ADC_DATAALIGN_RIGHT);//数据为右对齐
/* enable ADC interface */
adc_enable();
/* ADC calibration and reset calibration */
adc_calibration_enable();
/* ADC SCAN function enable */
adc_special_function_config(ADC_SCAN_MODE, ENABLE);//使能扫描模式
/* ADC continuous mode function enable */
adc_special_function_config(ADC_CONTINUOUS_MODE, ENABLE); //连续模式
/* ADC DMA function enable */
adc_dma_mode_enable();//使用ADC DMA, ADC的数据将会存入DMA模块中,这是定义的DMA数据空间为ad_value[]
adc_software_trigger_enable(ADC_REGULAR_CHANNEL);// 软件出发一次采样
}
原来就这个简单。
这里还要注意一个问题,就是采样时间,采样时间越短,输入的阻抗越小,这是如果你的信号是经过电阻分压后接入单片机的,那输入阻抗会改变电路设计上的分压比例,这时就要通过测量校准实际的比例值,比如电压经过300k+200K的电阻接到地,从两个电阻中间取信号,按电阻比例算分压比例是2/(3+2)=0.4,但若设置采样时间为1.5T,实际测出的比例是0.3355。
另一个是基准电压问题,如果VDDA不怎么稳定,会导致调试代码是容易中断,还有就是采集到的信号和实际偏差很大,这是可以通过采集弹片内部1.2V基准电压Vrefin得到的值反推出实际的VDDA的值,即实际采样值Vin=1.2xVrefinADC/VrefinADC.
上一篇:stm32——ucos的中断使用
下一篇:stm32变更外部晶振时时钟配置