完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
芯片:GD32F350 运行在8M
目标:每10ms读取三个adc通道,并且通过DMA传输 说明:本次使用ADC的定时扫描模式,由定时器触发ADC采集转换 ADC扫描模式预先设定好读取的通道,比如ch4 ch5 ch8,当触发adc时候就会连续采集三个通道的数据,通过dma传输到内存,过程(触发-》4-》5-》8-》触发-》4-》5-》8-》触发-》4-》5-》8-》触发) 注意是触发一次即转换三个通道的数据,而不是触发一次转换一个通道 1.配置DMA传输 //adc 的dma是否传输完成标志位 bool flag_DMA_ADC_accomplish = FALSE; //dma缓冲区 uint16_t battery_ADC_value_arry[ADC_VALUE_ARRY_SIZE] = {0}; /* 使能dma时钟 */ rcu_periph_clock_enable(RCU_DMA); /* dma初始化结构体 */ dma_parameter_struct dma_data_parameter; /* 复位DAM通道 */ dma_deinit(DMA_CH0); //ADC_RDATA是读取adc数据的寄存器 dma_data_parameter.periph_addr = (uint32_t)(&ADC_RDATA); dma_data_parameter.periph_inc = DMA_PERIPH_INCREASE_DISABLE; //battery_ADC_value_arry 是存储adc数据的内存数组 dma_data_parameter.memory_addr = (uint32_t)(&battery_ADC_value_arry); dma_data_parameter.memory_inc = DMA_MEMORY_INCREASE_ENABLE; dma_data_parameter.periph_width = DMA_PERIPHERAL_WIDTH_16BIT; dma_data_parameter.memory_width = DMA_MEMORY_WIDTH_16BIT; //从外设到内存 dma_data_parameter.direction = DMA_PERIPHERAL_TO_MEMORY; //这里的150是设置dma搬运数据的个数即3个通道共读取150个数据,每个通道读取50个,完成后会触发中断 dma_data_parameter.number = 150; dma_data_parameter.priority = DMA_PRIORITY_HIGH; dma_init(DMA_CH0, &dma_data_parameter); dma_circulation_enable(DMA_CH0); //设置dma中断优先级 nvic_irq_enable(DMA_Channel0_IRQn, 0, 0); /* enable DMA transfer complete interrupt */ dma_interrupt_enable(DMA_CH0, DMA_INT_FTF); /* 使能通道 */ dma_channel_enable(DMA_CH0); 2.配置ADC模式和通道 #define ADC_DMA_OUTPUT_INDEX (0u) #define ADC_DMA_BATTERY_INDEX (1u) #define ADC_DMA_USB_INDEX (2u) //开启时钟ADC的时钟 rcu_osci_on(RCU_IRC28M); while(ERROR == rcu_osci_stab_wait(RCU_IRC28M)); /* 配置ADC时钟 */ rcu_adc_clock_config(RCU_ADCCK_IRC28M_DIV2); /* 使能ADC时钟 */ rcu_periph_clock_enable(RCU_ADC); //========================================================= /* 端口时钟使能 */ rcu_periph_clock_enable(ADC_GPIO_CLK); /* 配置读取ADC引脚 */ gpio_mode_set(ADC_GPIO_PORT, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, ADC_GPIO_PIN); //========================================================= //连续转换关闭 adc_special_function_config(ADC_CONTINUOUS_MODE, DISABLE); //打开扫描模式 adc_special_function_config(ADC_SCAN_MODE, ENABLE); //========================================================= /* ADC 触发模式 用定时器1通道触发*/ adc_external_trigger_source_config( ADC_REGULAR_CHANNEL, ADC_EXTTRIG_REGULAR_T1_CH1); /* 数据对齐方式 */ adc_data_alignment_config(ADC_DATAALIGN_RIGHT); /* ADC分辨率 12B */ adc_resolution_config(ADC_RESOLUTION_12B); //========================================================= /* ADC channel 个数配置 */ adc_channel_length_config( ADC_REGULAR_CHANNEL, _ADC_VALUE_NUMBER); /* 配置ADC通道 */ adc_regular_channel_config(ADC_DMA_OUTPUT_INDEX , ADC_CHANNEL_4, ADC_SAMPLETIME_239POINT5); //输出功率 adc_regular_channel_config(ADC_DMA_BATTERY_INDEX, ADC_CHANNEL_5, ADC_SAMPLETIME_239POINT5); //电池通道 adc_regular_channel_config(ADC_DMA_USB_INDEX , ADC_CHANNEL_8, ADC_SAMPLETIME_239POINT5); //USB电压 //使能adc规则通道外部触发器 adc_external_trigger_config(ADC_REGULAR_CHANNEL, ENABLE); /* 开启ADC DMA */ adc_dma_mode_enable(); /* ADC使能 */ adc_enable(); delay_1ms(2U); /* ADC校准复位 */ adc_calibration_enable(); 3.配置定时器定时触发 //将定时器配置成周期10ms timer_oc_parameter_struct timer_ocintpara; timer_parameter_struct timer_initpara; rcu_periph_clock_enable(RCU_TIMER1); /* TIMER1 configuration */ //这里需要注意!!!!!因为我的主频是8M所以定时器这样配置,如果不一样,需要根据实际频率来调节 timer_initpara.prescaler = 8-1; timer_initpara.alignedmode = TIMER_COUNTER_EDGE; timer_initpara.counterdirection = TIMER_COUNTER_UP; timer_initpara.period = 10*1000; timer_initpara.clockdivision = TIMER_CKDIV_DIV1; timer_initpara.repetitioncounter = 0U; timer_init(TIMER1,&timer_initpara); /* CH0 configuration in PWM mode1 */ timer_ocintpara.ocpolarity = TIMER_OC_POLARITY_HIGH; timer_ocintpara.outputstate = TIMER_CCX_ENABLE; timer_channel_output_config(TIMER1, TIMER_CH_1, &timer_ocintpara); //这里设置比较值是5*1000 5ms是触发点,但是由于是周期性,所以每次采集也是等间距的 timer_channel_output_pulse_value_config(TIMER1, TIMER_CH_1, 5*1000); 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); timer_auto_reload_shadow_enable(TIMER1); // 可以尝试让他输出PWM用示波器查看配置是否正确 // gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_0); // gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,GPIO_PIN_0); // gpio_af_set(GPIOA, GPIO_AF_2, GPIO_PIN_0); 4.中断函数和获取足够数据后进行数据处理 //当传输完成足够的数据后,就关闭定时器,设置标志位,进行处理,可以在中断中处理, //也可以在其他地方处理,看个人习惯 void DMA_Channel0_IRQHandler(void) { //传输完成标志位 if(dma_interrupt_flag_get(DMA_CH0, DMA_INT_FLAG_FTF)) { //设置标志位 DMA完成了 flag_DMA_ADC_accomplish = TRUE; //关闭定时器,停止继续读取数据 timer_disable(TIMER1); //清除全部标志位 dma_interrupt_flag_clear(DMA_CH0, DMA_INT_FLAG_G); } } 数据处理,这里我就做了个简单的求平均 //dma平均之后的值 uint32_t voltage_raw_value[3] = {0}; //DMA传输完成 这里进行转换 if(TRUE == flag_DMA_ADC_accomplish) { //清除之前的数据 memset(voltage_raw_value,0,sizeof(voltage_raw_value)); for(int i = 0;i 《 ADC_VALUE_ARRY_SIZE;i += 3) { voltage_raw_value[0] += battery_ADC_value_arry[i + 0]; voltage_raw_value[1] += battery_ADC_value_arry[i + 1]; voltage_raw_value[2] += battery_ADC_value_arry[i + 2]; } } float tmp = 0; for(int i = 0;i 《 _ADC_VALUE_NUMBER;i += 1) { tmp = voltage_raw_value[i]; //这里除50是求平均值 tmp = tmp / 50; voltage_raw_value[i] = (uint16_t)tmp; } |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1801 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1629 浏览 1 评论
1096 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
735 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1684 浏览 2 评论
1944浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
745浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
579浏览 3评论
601浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
565浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-27 12:44 , Processed in 0.932590 second(s), Total 76, Slave 60 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (威廉希尔官方网站 图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号