历史上的今天
今天是:2024年09月06日(星期五)
2019年09月06日 | STM32 ADC多通道采样声音传感器和环境光传感器
2019-09-06 来源:eefocus
一、DMA
直接存储器存取(Direct Memory Access,DMA),直接存储器存取用来提供在外设和存储器之间或者存储器和存储器之间的高速数据传输。无须CPU的干预,通过DMA数据可以快速地移动。这就节省了CPU的资源来做其他操作。
二、ADC连续模式和扫描模式
ADC单通道时,只进行一次ADC转换,关闭连续转换模式,扫描模式关闭,这样ADC通道转换完成后停止,等待ADC转换的下一次启动。进行连续ADC转换时,ADC配置为连续转换模式,扫描模式关闭,ADC通道,转换一次后,接着进行下一次转换,不断连续。
ADC多通道时,要使能扫描模式。如果关闭连续转换模式,ADC多个通道,按照配置的顺序依次转换一次完成后,就停止转换。使能连续转换模式,ADC多个通道按照配置的顺序依次转换完成后,接着继续从头按照配置顺序依次转换,不断连续。
当多通道开启扫描模式时,不能直接读取AD转换数据,需要通过DMA方式读取
三、STM32CubeMx配置
声音传感器模块

光传感器模块

1.将PA4和PA6配置成ADC模式


2.打开ADC1的通道9和通道11,发现PA4和PA6变成绿色,GPIO模式也自动变成ADC转换模式

3.使能外部高速时钟

4.然后是配置时钟点击Clock Configuration,由于先打开了ADC而没有配置时钟,点到时钟配置时会显示

点No就好了,继续配置

5.使能DMA,增量地址选择内存,数据长度为字,连续传输模式

6.配置ADC参数

ADC 要完成对输入电压的采样需要若干个 ADC_CLK 周期,计算公式:
TCONV = 采样时间 + 12.5,所以ADC采样周期 = (2.5+12.5)= 15个周期,ADC完成采样的时间 = 1/fadc_clk * (ADC采样周期)。
7.使能ADC中断

8.使能串口

生成代码
四、Keil编写程序
在uart.c中做printf、scanf的重定向以便于串口通信
#include #ifdef __GNUC__ #define PUTCHAR_PROTOTYPE int __io_putchar(int ch) #else #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f) #endif PUTCHAR_PROTOTYPE { HAL_UART_Transmit(&huart1 , (uint8_t *)&ch, 1, 0xFFFF); return ch; } int fgetc(FILE *f) { uint8_t ch; HAL_UART_Receive(&huart1,(uint8_t *)&ch,1,0xfff); return ch; } 在adc.c中void MX_ADC1_Init(void)是ADC的初始化,与STM32CubeMX中配置的一样,也可以在此处修改 第一种ADC多通道采样方法: 1.在main.c定义一个数组作为转换数据缓存数组 /* USER CODE BEGIN 1 */ uint32_t ADC_Value[100]; uint8_t i ; uint32_t ad1,ad2 ; /* USER CODE END 1 */ 2.在while(1)前函数去开启ADC转换和DMA传输 /* USER CODE BEGIN 2 */ HAL_ADC_Start_DMA(&hadc1,(uint32_t*)&ADC_Value,100); /* USER CODE END 2 */ 3.DMA采用了连续传输的模式,ADC采集到的数据会不断传到到存储器中(此处即为数组ADC_Value)。数组里面的数据会不断被刷新。由于ADC顺序先是通道9(声音传感器)再是通道11(环境光传感器),所以存到ADC_Value[0]的是声音传感器ADC采集到的数据,ADC_Value[1]是环境光传感器ADC采集的数据,依此类推数组偶数存的是通道9(声音传感器)ADC采样值,数组级数存的是通道11(环境光传感器)ADC采样值。 /* USER CODE BEGIN WHILE */ while (1) { HAL_Delay(500); for(i = 0,ad1 = 0, ad2 = 0; i<100;) { ad1 += ADC_Value[i++] ; ad2 += ADC_Value[i++] ; } ad1 /=50 ; ad2 /=50 ; printf("rn******** ADC DMA Example ********rnrn"); printf("adc1 = %drn",ad1); printf("adc2 = %drn",ad2); printf("Voice Voltage: %.3fVrn",ad1*3.3f/4096); printf("Light Voltage: %.3fVrn",ad2*3.3f/4096); printf("rn********End ADC Example ********rn"); HAL_Delay(1000); /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ 将数组偶数下标数据加起来求平均值得到通道9(声音传感器)ADC采样值,将数组偶数下标数据加起来求平均值得到通道11(光传感器)ADC采样值,减小误差,再将数据转换为电压值。 ADC采样值到电压的转换: ADC12位分辨率,也就是说ADC模块读到的数据是12位的数据。。二进制的12位可表示0-4095个数。 电压值 = ADC采样值*(3.3V/4096) 第二种ADC多通道采样方法: ADC的几个回调函数: void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc); void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef* hadc); void HAL_ADC_LevelOutOfWindowCallback(ADC_HandleTypeDef* hadc); void HAL_ADC_ErrorCallback(ADC_HandleTypeDef *hadc); ADC中断、DMA传输、看门狗超过阀值、发生Adc错误,这些函数返回前都调用了Callback函数。用来在非中断模式下处理Adc数据,如果想进行一些操作可以直接修改Callback函数。 查看HAL_ADC_Start_DMA()函数 在HAL_ADC_Start_DMA()里会设置函数ADC_DMAConvCplt 在ADC_DMAConvCplt里有回调函数HAL_ADC_ConvCpltCallback() HAL_ADC_ConvCpltCallback()是虚函数,需要重新定义。 因为ADC转换和DMA传输很快,采样到的值可能还没读出来就被新的覆盖掉,可设置标志位当采样到的值传输到DMA之后停止,等到把DMA中的值读出来再启动,这就需要用到回调函数 在main函数 1.设置全局变量标志位 /* USER CODE BEGIN 0 */ int flag = 0 ; /* USER CODE END 0 */ 2.定义一个数组作为转换数据缓存数组,因为每次转换传输之后都会暂停等待数据被读出来所以可以设置数组小一点 /* USER CODE BEGIN 1 */ uint32_t ADC_Value[2]; /* USER CODE END 1 */ 3.ADC转换和DMA数组传输开始 /* USER CODE BEGIN 2 */ HAL_ADC_Start_DMA(&hadc1,(uint32_t*)&ADC_Value,2); /* USER CODE END 2 */ 4.在main函数外定义虚函数HAL_ADC_ConvCpltCallback回调函数,当ADC转换和DMA传输完成后,将标志位置为1并停止ADC转换和DMA传输 /* USER CODE BEGIN 4 */ void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) { flag=1; HAL_ADC_Stop_DMA(hadc); } /* USER CODE END 4 */ 5.在main函数while(1)里,当标志位为1的时候,将标志位置0并将采样值读出来,然后启动ADC转换和DMA传输。 /* USER CODE BEGIN WHILE */ while (1) { if(flag==1) { flag=0; HAL_Delay(200); printf("rn******** ADC DMA Example ********rnrn"); printf("rnch1 = %drn",ADC_Value[0]); HAL_Delay(200); printf("ch2 = %drn",ADC_Value[1]); printf("Voice Voltage: %.3fVrn",ADC_Value[0]*3.3f/4096); printf("Light Voltage: %.3fVrn",ADC_Value[1]*3.3f/4096); printf("rn********End ADC Example ********rn"); HAL_Delay(1000) ; } HAL_ADC_Start_DMA(&hadc1, (uint32_t*)&ADC_Value, 2); /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ 1.4秒ADC采样转换一次,这个多通道采集的方法误差比较大 五、测试 用手机手电筒照在环境光传感器上测试 用手机对着声音传感器放音乐






上一篇:STM32 CubeMX按键中断
下一篇:STM32L4 PWM蜂鸣器
史海拾趣
|
来源:http://www.ourdev.cn/bbs/bbs_content.jsp?bbs_sn=1398508&bbs_page_no=1&bbs_id=9999 前言 想了很久,要不要写这篇文章?最后觉得对操作系统感兴趣的人还是很多,写吧.我不一定能造出玉,但我可以抛出砖. 包括我在内的很多人都对51使用 ...… 查看全部问答> |
|
我把inline函数放到一个文件单独文件 有些函数比如说 FixPoint FixPoint::operator * ( const FixPoint& fp ) 这个函数在程序里面频繁调用 使用__asm{}加入arm汇编代码..不能编译通过.. nonstandard extension used : \'__asm\' keyword not s ...… 查看全部问答> |
|
遥控是TC9012,它采用的38kHz的载波(一个载波周期35us),载波占空比1/3,经过调制后发送波形是9ms的引导码(前4.5ms由载波构成,后4.5ms是载波关断)和33bit的数据构成。比特1是0.56ms的载波和1.69ms的载波关断构成,比特0是0.56ms的载波和0.565ms的 ...… 查看全部问答> |
|
继TI Stellaris Cortex-M3 的Sandstorm(沙暴)、Fury Class(狂暴)、Dustdevil Class(旋风)之后,Tempest Class(飓风)系列已开始全球批量供应。Stellaris基于实现了革命性突破的ARM Cortex-M3技术之上,是业界领先的高可靠性实时微处理 ...… 查看全部问答> |
|
全新3.5寸tft 触摸液晶屏51,avr,pic,stm,430可以直接驱动接口:16,18位接口可选39pinic: r61505u ili9320 26万色提供51测试代码,初始化代码,接口资料,ic资料 如果有人需要的 我可以负责联系商家,估计价格会在3 ...… 查看全部问答> |




