完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
用cube生成一个用定时器触发ADC1,ADC2同步采集的程序,单片机选择的是STM32L476RGT6,用定时器2进行ADC采集触发,更改定时器2的定时周期便可以更改ADC的采样周期,ADC1和ADC2使用同步规则模式,并用DMA进行数据的传输。
STM32的ADC采样完成总共需要的时间是 ADC完成采样时间=采样周期+12个转换周期 举个例子,假如ADC的时钟是15MHz,采样周期是3个周期,3个采样周期加上12个转换周期,一共是15个周期,因为时钟是15MHz,所以完成一次ADC转换总共需要的时间就是1us。 STM32L476RGT6的ADC时钟是32MHZ,采样周期最短是2.5个周期,最快完成一次采集的时间大约是0.45us,因此,定时器触发的周期一定要大于这个时长。 参考 STM32参考手册 里面对于ADC同步规则模式的介绍。 Cube生成的过程 时钟源配置 首先时钟源选择 晶体/陶瓷谐振器, 调试方式配置 然后在sys里面选择调试方式为Serial Wire 定时器配置 定时器1选择PWM输出模式,定时器的时钟是80MHz,进行2分频,计数周期是80,生成一个频率是500KHz,占空比为50%的PWM波,用于验证ADC的采样速率。 定时器2的时钟源选择内部时钟,2分频,40计数周期,实现1MHz的ADC触发。Trigger Event Selection TRGO 一定要选择 Update Event ,不然不会触发ADC。 ADC配置 ADC1的通道是12,ADC1和ADC2都有通道打开的情况才会出现双通道的模式选择,如果只有一个独立模式,可以先打开一个ADC2的通道,再来ADC1里面进行模式选择。模式选择双通道同步规则模式,触发源选择定时器2上升沿触发,采样周期是2.5个周期,其余的选项默认设置就行。 ADC2的通道是15,配置默认,ADC2一定要与ADC1的采样周期相同 DMA配置 DMA只需要给ADC1添加一个DMA通道,ADC2不用配置。ADC1添加的DMA模式选择循环传输,数据长度都选择Word。 串口配置 串口选择串口2,配置默认 中断配置 配置完成后的引脚图 时钟树配置 单片机运行的频率是80MHz,ADC采集频率是32MHz。 生成工程代码 上述都配置完成后便可以生成代码啦, 添加程序 main.cl里面需要添加的程序 在初始化完成后,while循环之前添加该段代码, /* USER CODE BEGIN 2 */ HAL_TIMEx_PWMN_Start(&htim1,TIM_CHANNEL_1); // 开启频率500KHz占空比为50%的PWM波 HAL_ADCEx_Calibration_Start(&hadc1, ADC_SINGLE_ENDED); // 对ADC进行校准,如果没有进行校准采集到的数据会有偏差 HAL_ADCEx_Calibration_Start(&hadc2, ADC_SINGLE_ENDED); HAL_TIM_Base_Start(&htim2); // 开启定时器2 用于触发ADC采集, 更改定时器2的频率便可以更改ADC的采样速率 HAL_ADC_Start(&hadc2); // 开启ADC2 /* USER CODE END 2 */ 在while循环里面添加下段代码 /* USER CODE BEGIN 3 */ printf("开始数据采集rn"); adc_complete = 0; // ADC采集完成标志 置零 HAL_ADCEx_MultiModeStart_DMA(&hadc1, (uint32_t*)&ADC_Value, sample_point); //开始同步采集ADC while(adc_complete == 0){HAL_Delay(5);} //等待ADC采集完成 printf("数据采集完成rn"); HAL_ADCEx_Calibration_Start(&hadc1, ADC_SINGLE_ENDED); // 对ADC进行校准 HAL_ADCEx_Calibration_Start(&hadc2, ADC_SINGLE_ENDED); for(i = 0, ad1 = 0, ad2 = 0; i { ADC_1[ad1++] = (uint16_t)ADC_Value; ADC_2[ad2++] = (uint16_t)(ADC_Value>>16); } for(i = 0; i printf("rn"); for(i = 0; i printf("rn"); for(i = 0; i printf("rn"); HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin); HAL_Delay(8000); /* USER CODE END 3 */ usart.c里面添加代码 /* USER CODE BEGIN 1 */ #ifdef __GNUC__ /*** With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf set to 'Yes') calls __io_putchar() */ #define PUTCHAR_PROTOTYPE int __io_putchar(int ch) #else #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f) #endif /* __GNUC__ */ /*** @brief Retargets the C library printf function to the USART. * @param None * @retval None*/ PUTCHAR_PROTOTYPE { /* Place your implementation of fputc here */ /* e.g. write a character to the EVAL_COM1 and Loop until the end of transmission */ HAL_UART_Transmit(&huart2, (uint8_t *)&ch, 1, 0xFFFF); //printf使用串口2输出 return ch; } /* USER CODE END 1 */ adc.c里面添加代码 /* USER CODE BEGIN 1 */ /* ADC采集完成后会进入该回调函数, 标记ADC转换完成并停止转换, 以免之前采集到的数据被覆盖*/ void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) { if(hadc->Instance==ADC1) { adc_complete = 1; // 标记ADC采集完成 HAL_ADCEx_MultiModeStop_DMA(&hadc1); // 停止ADC采集 } } /* USER CODE END 1 */ 验证 由于在家里没有信号源,也没有其他的单片机,验证就简单的输出了一个PWM波给ADC1,2进行采集来看现象。 将程序编译下载到单片机上,由于ADC1的12通道直接连在了定时器1输出PWM波的引脚上,PWM频率是500KHz,占空比是50%,所以ADC1应该采集到的的数据,是一个4095,之后一个0,ADC2的15通道悬空,所以ADC2的数据应该是乱的,串口显示的数据如图所示。 **现在将ADC2的15通道与ADC1的12通道连接在一起,采集到的数据ADC1和ADC2应该保持一致。**串口输出的数据如下图所示。 可以看出ADC1和ADC2采集到的数据保持一致。 现在更改定时器1的PWM波的频率和占空比,频率改为250KHz,占空比改为25%,ADC1和ADC2同时连接到该引脚,采集到的数据应该是1个4095, 3个0,并且ADC1和ADC2采集到的数据保持一致。串口输出的数据如下图所示。 从采集到的数据可以看出,验证基本成功。 完整的工程代码 完整的工程代码放到下面的链接里面了。工程代码 |
|
|
|
只有小组成员才能发言,加入小组>>
3318 浏览 9 评论
2995 浏览 16 评论
3494 浏览 1 评论
9063 浏览 16 评论
4088 浏览 18 评论
1182浏览 3评论
608浏览 2评论
const uint16_t Tab[10]={0}; const uint16_t *p; p = Tab;//报错是怎么回事?
600浏览 2评论
用NUC131单片机UART3作为打印口,但printf没有输出东西是什么原因?
2335浏览 2评论
NUC980DK61YC启动随机性出现Err-DDR是为什么?
1896浏览 2评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-24 21:10 , Processed in 1.126108 second(s), Total 80, Slave 61 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号