|
这个例子演示如何使用ADC以及如何对ADC采样值进行滤波处理。 |
Systick中断服务程序每个1ms启动并采集一次ADC值(PC4口线,可调电阻),并且对最近的20个样本进行求平均值。 |
平均值保存在全局变量g_usAdcValue中。主程序定时读取这个变量,并将值打印到串口1。 |
(1)程序在CPU内部Flash或者内部RAM执行时,样本个数取20个,则采样值非常稳定(1个字跳动) |
(2)程序在外部SRAM运行时,由于3.3V电源波动,因此采样值跳动较大。 |
请用串口线将开发板的COM1口连接到PC机的串口(或者USB串口),然后打开超级终端软件(XP自带的或者SecureCRT |
- 调节开发板上的可调电阻,超级终端界面上会显示一个不断旋转的字符 + 实时的ADC平均值 |
************************************************************* |
************************************************************* |
请调节开发板上的精密可调电阻,观察ADC采样值的变化 |
/ PC4口线ADC采样值 = 2149 , 电压 = 1731mV |
对于Keil MDK,为了避免中文字符串告警,需要在C/C++编译选项中增加 --diag_suppress=870 参数。 |
- /*
- *********************************************************************************************************
- *
- * 模块名称 : 主程序模块。
- * 文件名称 : main.c
- * 版 本 : V2.0
- * 说 明 : ADC采样和滤波例程。
- * 修改记录 :
- * 版本号 日期 作者 说明
- * v1.0 2011-08-27 armfly ST固件库V3.5.0版本。
- * v2.0 2011-10-16 armfly 优化工程结构。
- *
- *********************************************************************************************************
- */
- #include "stm32f10x.h" /* 如果要用ST的固件库,必须包含这个文件 */
- #include <stdio.h> /* 因为用到了printf函数,所以必须包含这个文件 */
- #include "bsp_usart.h" /* printf函数定向输出到串口,所以必须包含这个文件 */
- #include "bsp_led.h" /* LED指示灯驱动模块 */
- #include "bsp_button.h" /* 按键驱动模块 */
- #include "bsp_timer.h" /* systick定时器模块 */
- /* 定义例程名和例程发布日期 */
- #define EXAMPLE_NAME "ADC采样和滤波例程"
- #define EXAMPLE_DATE "2011-10-16"
- #define DEMO_VER "2.0"
- #define SAMP_COUNT 20 /* 样本个数,表示200ms内的采样数据求平均值 */
- /*
- 实际测试数据:
- (1)程序在CPU内部Flash或者内部RAM执行时,样本个数取20个,则采样值非常稳定
- (2)程序在外部SRAM运行时,由于3.3V电源波动,因此采样值跳动较大。
- */
- /* 仅允许本文件内调用的函数声明 */
- static void InitBoard(void);
- static void PrintfLogo(void);
- static uint16_t GetADC(void);
- static void ADC_Configuration(void);
- uint16_t g_usAdcValue; /* ADC 采样值的平均值 */
- /*
- *********************************************************************************************************
- * 函 数 名: main
- * 功能说明: c程序入口
- * 形 参:无
- * 返 回 值: 错误代码(无需处理)
- *********************************************************************************************************
- */
- int main(void)
- {
- uint16_t usValue;
- /*
- 由于ST固件库的启动文件已经执行了CPU系统时钟的初始化,所以不必再次重复配置系统时钟。
- 启动文件配置了CPU主时钟频率、内部Flash访问速度和可选的外部SRAM FSMC初始化。
-
- 系统时钟缺省配置为72MHz,如果需要更改,可以修改:
- \Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x\system_stm32f10x.c
- 中配置系统时钟的宏。
- */
-
- InitBoard(); /* 为了是main函数看起来更简洁些,我们将硬件初始化的代码封装到这个函数 */
- PrintfLogo(); /* 打印例程Logo到串口1 */
- printf("请调节开发板上的精密可调电阻,观察ADC采样值的变化\r\n");
- ADC_Configuration(); /* 配置PC4 为ADC1_IN14 */
- bsp_StartTimer(1, 300); /* 定时器0周期 200毫秒 */
- /* 进入主程序循环体 */
- while (1)
- {
- CPU_IDLE(); /* 这个宏在bsp_timer.h 中定义,目前定义为空。用户可以修改这个宏实现CPU休眠和喂狗 */
- if (bsp_CheckTimer(1)) /* 定时到 */
- {
- bsp_StartTimer(1, 300); /* 启动下个定时周期 */
- usValue = GetADC();
- /* 注意: 末尾只有 \r回车, 没有\n换行,可以使PC超级终端界面稳定在1行显示 */
- {
- /* 超级终端界面上会显示一个不断旋转的字符
- 增加这个功能,是为了避免程序死机的假象,因为ADC采样值很稳定
- */
- static uint8_t pos = 0;
- if (pos == 0)
- printf("|");
- else if (pos == 1)
- printf("/");
- else if (pos == 2)
- printf("-");
- else if (pos == 3)
- printf("\\"); /* 注意:这个特殊字符需要转义 */
- if (++pos >= 4)
- {
- pos = 0;
- }
- printf(" PC4口线ADC采样值 = %5d , 电压 = %4dmV\r",
- usValue, ((uint32_t)usValue * 3300) / 4095);
- }
- }
- /* 这个地方可以插入 GetKey(), 扩充对按键的响应代码 */
- }
- }
- /*
- *********************************************************************************************************
- * 函 数 名: ADC_Configuration
- * 功能说明: 配置ADC, PC4模式
- * 形 参:无
- * 返 回 值: 无
- *********************************************************************************************************
- */
- static void ADC_Configuration(void)
- {
- GPIO_InitTypeDef GPIO_InitStructure;
- ADC_InitTypeDef ADC_InitStructure;
- __IO uint16_t ADCConvertedValue;
- /* 使能 ADC1 and GPIOC clock */
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOC, ENABLE);
- /* 配置PC4为模拟输入(ADC Channel14) */
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
- GPIO_Init(GPIOC, &GPIO_InitStructure);
- /* 配置ADC1, 不用DMA, 用软件触发 */
- ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
- ADC_InitStructure.ADC_ScanConvMode = ENABLE;
- ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
- ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
- ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
- ADC_InitStructure.ADC_NbrOfChannel = 1;
- ADC_Init(ADC1, &ADC_InitStructure);
- /* 配置ADC1 规则通道14 channel14 configuration */
- ADC_RegularChannelConfig(ADC1, ADC_Channel_14, 1, ADC_SampleTime_55Cycles5);
- /* 使能ADC1 DMA功能 */
- ADC_DMACmd(ADC1, ENABLE);
- /* 使能 ADC1 */
- ADC_Cmd(ADC1, ENABLE);
- /* 使能ADC1 复位校准寄存器 */
- ADC_ResetCalibration(ADC1);
- /* 检查ADC1的复位寄存器 */
- while(ADC_GetResetCalibrationStatus(ADC1));
- /* 启动ADC1校准 */
- ADC_StartCalibration(ADC1);
- /* 检查校准是否结束 */
- while(ADC_GetCalibrationStatus(ADC1));
- /* 软件启动ADC转换 */
- ADC_SoftwareStartConvCmd(ADC1, ENABLE);
- }
- /*
- *********************************************************************************************************
- * 函 数 名: AdcPro
- * 功能说明: ADC采样处理,插入1ms systick中断进行调用
- * 形 参:无
- * 返 回 值: 无
- *********************************************************************************************************
- */
- void AdcPro(void)
- {
- static uint16_t buf[SAMP_COUNT];
- static uint8_t write;
- uint32_t sum;
- uint8_t i;
- buf[write] = ADC_GetConversionValue(ADC1);
- if (++write >= SAMP_COUNT)
- {
- write = 0;
- }
- /* 下面这段代码采用求平均值的方法进行滤波
- 也可以改善下,选择去掉最大和最下2个值,使数据更加精确
- */
- sum = 0;
- for (i = 0; i < SAMP_COUNT; i++)
- {
- sum += buf[i];
- }
- g_usAdcValue = sum / SAMP_COUNT; /* ADC采样值由若干次采样值平均 */
- ADC_SoftwareStartConvCmd(ADC1, ENABLE); /* 软件启动下次ADC转换 */
- }
- /*
- *********************************************************************************************************
- * 函 数 名: GetADC
- * 功能说明: 读取ADC采样的平均值
- * 形 参:无
- * 返 回 值: 无
- *********************************************************************************************************
- */
- static uint16_t GetADC(void)
- {
- uint16_t ret;
- /* 因为 g_AdcValue 变量在systick中断中改写,为了避免主程序读变量时被中断程序打乱导致数据错误,因此需要
- 关闭中断进行保护 */
- /* 进行临界区保护,关闭中断 */
- __set_PRIMASK(1); /* 关中断 */
- ret = g_usAdcValue;
- __set_PRIMASK(0); /* 开中断 */
- return ret;
- }
- /*
- *********************************************************************************************************
- * 函 数 名: InitBoard
- * 功能说明: 初始化硬件设备
- * 形 参:无
- * 返 回 值: 无
- *********************************************************************************************************
- */
- static void InitBoard(void)
- {
- /* 配置串口,用于printf输出 */
- bsp_InitUart();
-
- /* 配置LED指示灯GPIO */
- bsp_InitLed();
- /* 配置按键GPIO, 必须在bsp_InitTimer之前调用 */
- bsp_InitButton();
- /* 初始化systick定时器,并启动定时中断 */
- bsp_InitTimer();
- }
- /*
- *********************************************************************************************************
- * 函 数 名: PrintfLogo
- * 功能说明: 打印例程名称和例程发布日期, 接上串口线后,打开PC机的超级终端软件可以观察结果
- * 形 参:无
- * 返 回 值: 无
- *********************************************************************************************************
- */
- static void PrintfLogo(void)
- {
- printf("*************************************************************\n\r");
- printf("* 例程名称 : %s\r\n", EXAMPLE_NAME); /* 打印例程名称 */
- printf("* 例程版本 : %s\r\n", DEMO_VER); /* 打印例程版本 */
- printf("* 发布日期 : %s\r\n", EXAMPLE_DATE); /* 打印例程日期 */
- /* 打印ST固件库版本,这3个定义宏在stm32f10x.h文件中 */
- printf("* 固件库版本 : %d.%d.%d\r\n", __STM32F10X_STDPERIPH_VERSION_MAIN,
- __STM32F10X_STDPERIPH_VERSION_SUB1,__STM32F10X_STDPERIPH_VERSION_SUB2);
- printf("* \n\r"); /* 打印一行空格 */
- printf("* QQ : 1295744630 \r\n");
- printf("* Email : armfly@qq.com \r\n");
- printf("* Copyright www.armfly.com 安富莱电子\r\n");
- printf("*************************************************************\n\r");
- }
复制代码
ADC采样和滤波例程.rar
(473 KB, 下载次数: 6)
|
|