渭南市住房和城乡建设部网站,数据库调用做wordpress,专门做同人h的网站,长葛网站建站之前已经介绍了几个ADC的笔记和实验了#xff0c;链接如下#xff1a;
关于ADC的笔记1_Mr_rustylake的博客-CSDN博客
STM32-ADC单通道采集实验_Mr_rustylake的博客-CSDN博客
STM32-单通道ADC采集#xff08;DMA读取#xff09;实验_Mr_rustylake的博客-CSDN博客
接下来…之前已经介绍了几个ADC的笔记和实验了链接如下
关于ADC的笔记1_Mr_rustylake的博客-CSDN博客
STM32-ADC单通道采集实验_Mr_rustylake的博客-CSDN博客
STM32-单通道ADC采集DMA读取实验_Mr_rustylake的博客-CSDN博客
接下来介绍这次的实验要求
通过ADC1通道0/1/2/3/4/5PA0/1/2/3/4/5采集测试电压并现实ADC转换的数字量和换算后的电压值。
首先确定我们的最小刻度Vref 3.3V所以0V Vin 3.3V所以最小刻度是3.3V / 40962^12。
接下来确定转换时间。采样时间239.5个ADC时钟周期为例可以得到转换时间为21us。
时间转换公式参考如下公式Tcvtmin12.5X周期(12.5 X)/(12MHz)21us。 下图是对应的通道表 这里的模式考虑到需要多通道扫描所以启动扫描模式并启动连续模式。通道数记得改为6注意设置通道数目和对应的转换顺序。
接下来编写函数的代码
先编写函数文件adc.h
#include ./BSP/ADC/adc.hADC_HandleTypeDef g_adc_nch_handle;
DMA_HandleTypeDef g_dma_nch_handle;
uint8_t g_adc_dma_sta; //标志DMA的传输是否完成void adc_nch_dam_init(uint32_t mar){ADC_ChannelConfTypeDef adc_ch_conf;__HAL_RCC_DMA1_CLK_ENABLE();g_dma_nch_handle.Instance DMA1_Channel1;g_dma_nch_handle.Init.Direction DMA_PERIPH_TO_MEMORY; //外设到内存g_dma_nch_handle.Init.PeriphInc DMA_PINC_DISABLE; //因为选取的是DMA1的数据寄存器选择不增量g_dma_nch_handle.Init.MemInc DMA_MINC_ENABLE; //对于存储器需要存储多个数据所以选择增量模式g_dma_nch_handle.Init.PeriphDataAlignment DMA_PDATAALIGN_HALFWORD; //外设数据位宽我们选择16位半字全字可以理解为全角中文字符g_dma_nch_handle.Init.MemDataAlignment DMA_MDATAALIGN_HALFWORD; //存储器数据位宽我们也选择16位半字g_dma_nch_handle.Init.Mode DMA_NORMAL; //选择普通模式因为在传输完成之后我们需要进行进一步操作现实我们获取到的值所以选择normalg_dma_handle.Init.Priority DMA_PRIORITY_MEDIUM; //只有1个DMA随便选HAL_DMA_Init(g_dma_nch_handle);//联系DMA和ADC的句柄__HAL_LINKDMA(g_adc_nch_handle, DMA_Handle, g_dma_nch_handle); //第二个参数为第一个ADC句柄的第三个成员指向对应的DMA句柄g_adc_nch_handle.Instance ADC1;g_adc_nch_handle.Init.DataAlign ADC_DATAALIGN_RIGHT; //右对齐g_adc_nch_handle.Init.ScanConvMode ADC_SCAN_ENABLE; //扫描g_adc_nch_handle.Init.ContinuousConvMode ENABLE; //连续模式g_adc_nch_handle.Init.NbrOfConversion 6; //转换通道数为66通道g_adc_nch_handle.Init.DiscontinuousConvMode DISABLE; //不用间断模式g_adc_nch_handle.Init.NbrOfDiscConversion 0; //无间断模式则无间断通道g_adc_nch_handle.Init.ExternalTrigConv ADC_SOFTWARE_START; //外部软件触发HAL_ADC_Init(g_adc_handle);adc_ch_conf.Channel ADC_CHANNEL_0;adc_ch_conf.Rank ADC_REGULAR_RANK_1; //转换顺序adc_ch_conf.SamplingTime ADC_SMAPLINGTIME_239CYCLES_5; //设置为最大值HAL_ADC_ConfigChannel(g_adc_nch_handle, adc_ch_conf);adc_ch_conf.Channel ADC_CHANNEL_1;adc_ch_conf.Rank ADC_REGULAR_RANK_2; //转换顺序adc_ch_conf.SamplingTime ADC_SMAPLINGTIME_239CYCLES_5; //设置为最大值HAL_ADC_ConfigChannel(g_adc_nch_handle, adc_ch_conf);adc_ch_conf.Channel ADC_CHANNEL_2;adc_ch_conf.Rank ADC_REGULAR_RANK_3; //转换顺序adc_ch_conf.SamplingTime ADC_SMAPLINGTIME_239CYCLES_5; //设置为最大值HAL_ADC_ConfigChannel(g_adc_nch_handle, adc_ch_conf);adc_ch_conf.Channel ADC_CHANNEL_3;adc_ch_conf.Rank ADC_REGULAR_RANK_4; //转换顺序adc_ch_conf.SamplingTime ADC_SMAPLINGTIME_239CYCLES_5; //设置为最大值HAL_ADC_ConfigChannel(g_adc_nch_handle, adc_ch_conf);adc_ch_conf.Channel ADC_CHANNEL_4;adc_ch_conf.Rank ADC_REGULAR_RANK_5; //转换顺序adc_ch_conf.SamplingTime ADC_SMAPLINGTIME_239CYCLES_5; //设置为最大值HAL_ADC_ConfigChannel(g_adc_nch_handle, adc_ch_conf);adc_ch_conf.Channel ADC_CHANNEL_5;adc_ch_conf.Rank ADC_REGULAR_RANK_6; //转换顺序adc_ch_conf.SamplingTime ADC_SMAPLINGTIME_239CYCLES_5; //设置为最大值HAL_ADC_ConfigChannel(g_adc_nch_handle, adc_ch_conf);HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 2, 3);HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);HAL_ADCEx_Calibration_Start(g_adc_nch_handle);HAL_DMA_Start_IT(g_dma_nch_handle, (uint32_t)ADC1-DR, mar, 0);HAL_ADC_Start_IT(g_adc_nch_handle, mar, 0);
}void HAL_ADC_MspInit(ADC_HandleTypeDef *hadc){if(hadc-Instance ADC1){GPIO_InitTypeDef gpio_init_struct;RCC_PeriphCLKInitTypeDef adc_clk_init {0};__HAL_RCC_GPIOA_CLK_ENABLE(); //使能ADC时钟__HAL_RCC_ADC1_CLK_ENABLE(); //使能GPIO时钟gpio_init_struct.Pin GPIO_PIN_0;gpio_init_struct.Mode GPIO_MODE_ANALOG; //模拟模式HAL_GPIO_Init(GPIOA, gpio_init_struct);gpio_init_struct.Pin GPIO_PIN_1;HAL_GPIO_Init(GPIOA, gpio_init_struct);gpio_init_struct.Pin GPIO_PIN_2;HAL_GPIO_Init(GPIOA, gpio_init_struct);gpio_init_struct.Pin GPIO_PIN_3;HAL_GPIO_Init(GPIOA, gpio_init_struct);gpio_init_struct.Pin GPIO_PIN_4;HAL_GPIO_Init(GPIOA, gpio_init_struct);gpio_init_struct.Pin GPIO_PIN_5;HAL_GPIO_Init(GPIOA, gpio_init_struct);adc_clk_init.PeriphClockSelection RCC_PERIPHCLK_ADC; //选择ADC外设时钟设置adc_clk_init.AdcClockSelection RCC_ADCPCLK2_DIV6; //选择6分频,72/612MHzHAL_RCCEx_PeriphCLKConfig(adc_clk_init, g_adc_nch_handle);}
}uint32_t adc_get_result(void){HAL_ADC_Start(g_adc_nch_handle);HAL_ADC_PollForConversion(g_adc_nch_handle, 10); //第二个参数比1大就行return (uint16_t)HAL_ADC_GetValue(g_adc_nch_handle);
}uint32_t adc_get_result_average(uint32_t ch, uint8_t times){uint32_t temp_val 0;uint8_t t;for(t 0; t times; t){temp_val adc_get_result();delay_ms(5);}return temp_val / times;
}void adc_dma_enable(uint16_t cndtr){/*ADC1-CR2 ~(1 0); //关闭ADCDMA1_Channel1-CCR ~(1 0);//关闭DMAwhile(DMA1_Channel1-CCR (1 0));DMA1_Channel1-CNDTR cndtr;DMA1_Channel1-CCR | (1 0); //开启DMAADC1-CR2 | (1 0); //开启ADCADC1-CR2 | (1 22); //触发规则组转换*///hal库法__HAL_ADC_DISABLE(g_adc_nch_handle);__HAL_DNA_DISABLE(g_dma_nch_handle);while(__HAL_DMA_GET_FLAG(g_dma_nch_handle, __HAL_DMA_GET_FLAG_INDEX(g_dma_nch_handle)));DMA1_Channel1-CNDTR cndtr;__HAL_DMA_ENABEL(g_dma_nch_handle);__HAL_ADC_ENABLE(g_adc_nch_handle);HAL_ADC_Start(g_adc_nch_handle);
}void DMA1_Channel1_IRQHandle(void){if(DMA1-ISR (1 1)){g_adc_dma_sta 1;DMA1-IECR | 1 1;}
}
接下来在编写函数文件的头文件adc.h
#ifndef __ADC_H
#define __ADC_H#include SYSTEM/sys/sys.h
#include BSP/DMA/dma.hextern ADC_HandleTypeDef g_adc_handle;void adc_nch_dam_init(uint32_t mar);
void HAL_ADC_MspInit(ADC_HandleTypeDef *hadc);
uint32_t adc_get_result(void);
uint32_t adc_get_result_average(uint32_t ch, uint8_t times);
void adc_dma_enable(uint16_t cndtr);
void DMA1_Channel1_IRQHandle(void);#endif
最后编写主函数代码main.c
#include ./SYSTEM/sys/sys.h
#include ./SYSTEM/usart/usart.h
#include ./SYSTEM/delay/delay.h
#include ./USMART/usmart.h
#include ./BSP/LED/led.h
#include ./BSP/LCD/lcd.h
#include ./BSP/ADC/adc.h#define ADC_DMA_BUF_SIZE 50 * 6 /* ADC DMA采集 BUF大小, 应等于ADC通道数的整数倍50表示转换50次 */
uint16_t g_adc_dma_buf[ADC_DMA_BUF_SIZE]; /* ADC DMA BUF */extern uint8_t g_adc_dma_sta; /* DMA传输状态标志, 0,未完成; 1, 已完成 */int main(void)
{uint16_t i,j;uint16_t adcx;uint32_t sum;float temp;HAL_Init(); /* 初始化HAL库 */sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */delay_init(72); /* 延时初始化 */usart_init(115200); /* 串口初始化为115200 */led_init(); /* 初始化LED */lcd_init(); /* 初始化LCD */adc_nch_dma_init((uint32_t)g_adc_dma_buf); /* 初始化ADC DMA采集 */lcd_show_string(30, 50, 200, 16, 16, STM32, RED);lcd_show_string(30, 70, 200, 16, 16, ADC 6CH DMA TEST, RED);lcd_show_string(30, 90, 200, 16, 16, ATOMALIENTEK, RED);lcd_show_string(30, 110, 200, 12, 12, ADC1_CH0_VAL:, BLUE);lcd_show_string(30, 122, 200, 12, 12, ADC1_CH0_VOL:0.000V, BLUE); /* 先在固定位置显示小数点 */lcd_show_string(30, 140, 200, 12, 12, ADC1_CH1_VAL:, BLUE);lcd_show_string(30, 152, 200, 12, 12, ADC1_CH1_VOL:0.000V, BLUE); /* 先在固定位置显示小数点 */lcd_show_string(30, 170, 200, 12, 12, ADC1_CH2_VAL:, BLUE);lcd_show_string(30, 182, 200, 12, 12, ADC1_CH2_VOL:0.000V, BLUE); /* 先在固定位置显示小数点 */lcd_show_string(30, 200, 200, 12, 12, ADC1_CH3_VAL:, BLUE);lcd_show_string(30, 212, 200, 12, 12, ADC1_CH3_VOL:0.000V, BLUE); /* 先在固定位置显示小数点 */lcd_show_string(30, 230, 200, 12, 12, ADC1_CH4_VAL:, BLUE);lcd_show_string(30, 242, 200, 12, 12, ADC1_CH4_VOL:0.000V, BLUE); /* 先在固定位置显示小数点 */lcd_show_string(30, 260, 200, 12, 12, ADC1_CH5_VAL:, BLUE);lcd_show_string(30, 272, 200, 12, 12, ADC1_CH5_VOL:0.000V, BLUE); /* 先在固定位置显示小数点 */adc_dma_enable(ADC_DMA_BUF_SIZE); /* 启动ADC DMA采集 */while (1){if (g_adc_dma_sta 1){/* 循环显示通道0~通道5的结果 */for(j 0; j 6; j) /* 遍历6个通道 */{sum 0; /* 清零 */for (i 0; i ADC_DMA_BUF_SIZE / 6; i) /* 每个通道采集了50次数据,进行50次累加 */{sum g_adc_dma_buf[(6 * i) j]; /* 相同通道的转换数据累加 */}adcx sum / (ADC_DMA_BUF_SIZE / 6); /* 取平均值 *//* 显示结果 */lcd_show_xnum(108, 110 (j * 30), adcx, 4, 12, 0, BLUE); /* 显示ADCC采样后的原始值 */temp (float)adcx * (3.3 / 4096); /* 获取计算后的带小数的实际电压值比如3.1111 */adcx temp; /* 赋值整数部分给adcx变量因为adcx为u16整形 */lcd_show_xnum(108, 122 (j * 30), adcx, 1, 12, 0, BLUE); /* 显示电压值的整数部分3.1111的话这里就是显示3 */temp - adcx; /* 把已经显示的整数部分去掉留下小数部分比如3.1111-30.1111 */temp * 1000; /* 小数部分乘以1000例如0.1111就转换为111.1相当于保留三位小数。 */lcd_show_xnum(120, 122 (j * 30), temp, 3, 12, 0X80, BLUE);/* 显示小数部分前面转换为了整形显示这里显示的就是111. */}g_adc_dma_sta 0; /* 清除DMA采集完成状态标志 */adc_dma_enable(ADC_DMA_BUF_SIZE); /* 启动下一次ADC DMA采集 */}LED0_TOGGLE();delay_ms(100);}
}
到这里我们的实验代码就写完了。