当前位置:网站首页>STM32H743VIT6配置ADC为1M采样率
STM32H743VIT6配置ADC为1M采样率
2022-08-03 14:51:00 【*Temporary】
外设总结
1M的采样率,对于32而言已经很高了,所以这边我们必然是需要使用DMA的,除此之外,我们选用定时器1作为触发源,方便随时修改采样频率的同时,也更为精准的设置采样频率为1M。
配置过程
首先是定时器的初始化过程。
static void ADC_TIME_Config(void){
TIM_HandleTypeDef TIM_HandleADC_TRIG = {
0};
TIM_OC_InitTypeDef TIM_OC_InitADC_TRIG = {
0};
HAL_TIM_Base_DeInit(&TIM_HandleADC_TRIG);
TIM_HandleADC_TRIG.Instance = TIM1;
TIM_HandleADC_TRIG.Init.Period = ADC_DMA_PWM_PERIODVALUE - 1;
TIM_HandleADC_TRIG.Init.Prescaler = 0;
TIM_HandleADC_TRIG.Init.CounterMode = TIM_COUNTERMODE_UP;
TIM_HandleADC_TRIG.Init.RepetitionCounter = 0;
HAL_TIM_Base_Init(&TIM_HandleADC_TRIG);
TIM_OC_InitADC_TRIG.OCMode = TIM_OCMODE_PWM1;
TIM_OC_InitADC_TRIG.OCPolarity = TIM_OCPOLARITY_LOW;
TIM_OC_InitADC_TRIG.Pulse = ADC_DMA_PWM_PERIODVALUE / 2;
if(HAL_TIM_OC_ConfigChannel(&TIM_HandleADC_TRIG, &TIM_OC_InitADC_TRIG, TIM_CHANNEL_1) != HAL_OK)
while(1);
if(HAL_TIM_OC_Start(&TIM_HandleADC_TRIG, TIM_CHANNEL_1) != HAL_OK)
while(1);
}
上面的重装载值和分频系数大伙自行根据自己工程的时钟频率修改即可,配置成1MHz即可。这边如果有朋友需要将输出比较的PWM引出到外部引脚上,可以在回调函数中加上下面这段程序,当然,不需要的话也可以不加,不影响触发ADC采集。
if(htim->Instance == TIM1){
__HAL_RCC_TIM1_CLK_ENABLE();
__HAL_RCC_GPIOE_CLK_ENABLE();
GPIO_Initure.Pin = GPIO_PIN_9; //PB0
GPIO_Initure.Mode = GPIO_MODE_AF_PP; //复用推完输出
GPIO_Initure.Pull = GPIO_PULLUP; //上拉
GPIO_Initure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_Initure.Alternate = GPIO_AF1_TIM1;
HAL_GPIO_Init(GPIOE,&GPIO_Initure);
}
然后就是重头戏,ADC+DMA配置代码。
void hy_ADC_DMA_Init(void){
ADC_Config_Choose |= 0x02;
DMA_HandleTypeDef DMA_HandleADC_Str = {
0};
ADC_ChannelConfTypeDef ADC_ChannelConfADCDMA_Str = {
0};
__HAL_RCC_DMA1_CLK_ENABLE();
HAL_DMA_DeInit(&DMA_HandleADC_Str);
DMA_HandleADC_Str.Instance = DMA1_Stream1;
DMA_HandleADC_Str.Init.Request = DMA_REQUEST_ADC1;
DMA_HandleADC_Str.Init.Direction = DMA_PERIPH_TO_MEMORY;
DMA_HandleADC_Str.Init.Mode = DMA_CIRCULAR;
DMA_HandleADC_Str.Init.MemInc = DMA_MINC_ENABLE;
DMA_HandleADC_Str.Init.PeriphInc = DMA_PINC_DISABLE;
DMA_HandleADC_Str.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
DMA_HandleADC_Str.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
DMA_HandleADC_Str.Init.Priority = DMA_PRIORITY_LOW; //优先级低
DMA_HandleADC_Str.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
DMA_HandleADC_Str.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
DMA_HandleADC_Str.Init.MemBurst = DMA_MBURST_SINGLE;
DMA_HandleADC_Str.Init.PeriphBurst = DMA_PBURST_SINGLE;
if(HAL_DMA_Init(&DMA_HandleADC_Str) != HAL_OK)
while(1);
HAL_NVIC_SetPriority(DMA1_Stream1_IRQn, 2, 0);
HAL_NVIC_EnableIRQ(DMA1_Stream1_IRQn);
__HAL_LINKDMA(&ADC_HandleDMA_Str, DMA_Handle, DMA_HandleADC_Str);
HAL_ADC_DeInit(&ADC_HandleDMA_Str);
ADC_HandleDMA_Str.Instance = ADC1;
ADC_HandleDMA_Str.Init.ClockPrescaler = ADC_CLOCKPRESCALER_PCLK_DIV4;
ADC_HandleDMA_Str.Init.Resolution = ADC_RESOLUTION_16B;
ADC_HandleDMA_Str.Init.ScanConvMode = ADC_SCAN_DISABLE;
ADC_HandleDMA_Str.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
ADC_HandleDMA_Str.Init.LowPowerAutoWait = DISABLE;
ADC_HandleDMA_Str.Init.ContinuousConvMode = DISABLE;
ADC_HandleDMA_Str.Init.NbrOfConversion = 1;
ADC_HandleDMA_Str.Init.DiscontinuousConvMode = DISABLE;
ADC_HandleDMA_Str.Init.NbrOfDiscConversion = 1;
ADC_HandleDMA_Str.Init.ExternalTrigConv = ADC_EXTERNALTRIG_T1_CC1;
ADC_HandleDMA_Str.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING;
ADC_HandleDMA_Str.Init.ConversionDataManagement = ADC_CONVERSIONDATA_DMA_CIRCULAR; /* DMA 循环模式接收 ADC转换的数据 */
ADC_HandleDMA_Str.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;
ADC_HandleDMA_Str.Init.OversamplingMode = DISABLE;
if(HAL_ADC_Init(&ADC_HandleDMA_Str) != HAL_OK)
while(1);
HAL_ADCEx_Calibration_Start(&ADC_HandleDMA_Str, ADC_CALIB_OFFSET, ADC_SINGLE_ENDED);
ADC_ChannelConfADCDMA_Str.Channel = ADC_CHANNEL_3;
ADC_ChannelConfADCDMA_Str.Offset = 0;
ADC_ChannelConfADCDMA_Str.Rank = ADC_REGULAR_RANK_1;
ADC_ChannelConfADCDMA_Str.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
ADC_ChannelConfADCDMA_Str.SingleDiff = ADC_SINGLE_ENDED;
ADC_ChannelConfADCDMA_Str.OffsetNumber = ADC_OFFSET_NONE;
if(HAL_ADC_ConfigChannel(&ADC_HandleDMA_Str, &ADC_ChannelConfADCDMA_Str) != HAL_OK)
while(1);
ADC_TIME_Config();
if(HAL_ADC_Start_DMA(&ADC_HandleDMA_Str, (uint32_t *)adc_dma_read_data, 1040) != HAL_OK)
while(1);
}
可以看出,上面我设置的是1040个数据,也就是说传输完成1040个数据之后我们会进入到DMA中断中,下面贴上DMA中断代码。
void DMA1_Stream1_IRQHandler(void){
static uint8_t dma_test_data[1] = {
0};
/* 传输完成中断 */
if((DMA1->LISR & DMA_FLAG_TCIF1_5) != RESET){
DMA1->LIFCR = DMA_FLAG_TCIF1_5;
dma_test_data[0]++;
if(dma_test_data[0] == 5){
HAL_NVIC_DisableIRQ(DMA1_Stream1_IRQn);
ADC_Disable(&ADC_HandleDMA_Str);
collect_flag = 1;
}
}
/* 半传输完成中断 */
if((DMA1->LISR & DMA_FLAG_HTIF1_5) != RESET){
DMA1->LIFCR = DMA_FLAG_HTIF1_5;
}
/* 传输错误中断 */
if((DMA1->LISR & DMA_FLAG_TEIF1_5) != RESET){
DMA1->LIFCR = DMA_FLAG_TEIF1_5;
}
/* 直接模式错误中断 */
if((DMA1->LISR & DMA_FLAG_DMEIF1_5) != RESET){
DMA1->LIFCR = DMA_FLAG_DMEIF1_5;
}
}
其他中断我们暂时不需要写中断处理,清除标志位即可,传输完成中断,我们可以在里边关闭ADC采集和DMA中断,然后设置一个标志位,标志位被置位后我们在主函数中对数据进行处理。
if(collect_flag){
collect_flag = 0;
for(i = 0; i < 1024; i++){
printf("data is:%d \n", adc_dma_read_data[i]);
delay_ms(1);
}
}
以上就是配置的全部过程。
问题所在
经过实测,1MHz的采样率是没问题的,我用这个频率去采集50KHz以及100KHz的正弦波是没有问题的,波形如下所示:
上面的波形看出,采集效果还是ok的,除开100k的时候可能是外界干扰的原因造成波形失真,这个大伙加上滤波电路之后或者软件再滤个波即可,但是当我把输入信号设置成10k之后,发现波形如下所示:
没错,1MHz采集10KHz的正弦波,波形失真,啥也不是。。。对此本人也是感到比较奇怪,当我把采样频率降为100k之后,波形就正常了,对此,有知道的朋友欢迎在评论区指出,谢谢。
边栏推荐
猜你喜欢
随机推荐
淘特:引擎还是包袱?
程序员面试必备PHP基础面试题 – 第十八天
输出一个整数的二进制形式
Clickhouse填坑记3:Left Join改Right Join导致统计结果错误
Role usage in Ansible
树莓派 USB摄像头 实现网络监控( MJPG-Streamer)
Taurus.MVC WebAPI 入门开发教程1:框架下载环境配置与运行(含系列目录)。
问题1:get和post的区别
兆骑科创创业大赛,双创服务平台,线上直播路演
兆骑科创高层次人才引进平台,创新创业赛事活动路演
彻底搞懂云桌面配置及实践踩坑【华为云至简致远】
一个在浏览器中看到的透视Cell实现
Day1:面试必考真题
leetcode 448. Find All Numbers Disappeared in an Array 找到所有数组中消失的数字(简单)
地球自转加快
php类的析构函数:__destruct
理解string类
进程通信的方式
20220801使用安信可的ESP-01S模块实现WIFI的UART传输功能
PAT乙级-B1009 说反话(20)