历史上的今天
返回首页

历史上的今天

今天是:2025年05月13日(星期二)

正在发生

2018年05月13日 | 关于Stm32定时器+ADC+DMA进行AD采样的实现

2018-05-13 来源:eefocus

注:此STM32单片机为STM32F103系列的
Stm32的ADC有DMA功能这都毋庸置疑,也是我们用的最多的!然而,如果我们要对一个信号(比如脉搏信号)进行定时采样(也就是隔一段时间,比如说2ms),有三种方法:

1、使用定时器中断每隔一定时间进行ADC转换,这样每次都必须读ADC的数据寄存器,非常浪费时间!

2、把ADC设置成连续转换模式,同时对应的DMA通道开启循环模式,这样ADC就一直在进行数据采集然后通过DMA把数据搬运至内存。但是这样做的话还得加一个定时中断,用来定时读取内存中的数据!

3、使用ADC的定时器触发ADC转换的功能,然后使用DMA进行数据的搬运!这样只要设置好定时器的触发间隔,就能实现ADC定时采样转换的功能,然后可以在程序的死循环中一直检测DMA转换完成标志,然后进行数据的读取,或者使能DMA转换完成中断,这样每次转换完成就会产生中断,我是采用第二种方法。下面上代码:我这里使用的单通道
//定时器初始化
void TIM2_Configuration(void)

 TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; 
 TIM_OCInitTypeDef TIM_OCInitStructure; 
 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 , ENABLE); 
 TIM_TimeBaseStructure.TIM_Period = 1999;//设置2ms一次TIM2比较的周期
 TIM_TimeBaseStructure.TIM_Prescaler = 71;//系统主频72M,这里分频71,相当于1000K的定时器2时钟 
 TIM_TimeBaseStructure.TIM_ClockDivision = 0x0; 
 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
 TIM_TimeBaseInit(TIM2, & TIM_TimeBaseStructure);
    
 TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;//下面详细说明 
 TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//TIM_OutputState_Disable; 
 TIM_OCInitStructure.TIM_Pulse = 1000; 
 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;//如果是PWM1要为Low,PWM2则为High 
 TIM_OC2Init(TIM2, & TIM_OCInitStructure);   
// TIM_InternalClockConfig(TIM2);
// TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Enable); 
// TIM_UpdateDisableConfig(TIM2, DISABLE);
}
//ADC_DMA初始化配置
void ADC_DMA_Config(void)
{
  DMA_InitTypeDef DMA_InitStructure; // 注:ADC为12位模数转换器,只有ADCConvertedValue的低12位有效
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);//使能DMA时钟
  DMA_DeInit(DMA1_Channel1);//开启DMA1的第一通道 
  DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;//DMA对应的外设基地址
  DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&ADCConvertedValue; //内存存储基地址
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //DMA的转换模式为SRC模式,由外设搬移到内存
  DMA_InitStructure.DMA_BufferSize = 1;//DMA缓存大小,1个
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //接收一次数据后,设备地址禁止后移
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable; //关闭接收一次数据后,目标内存地址后移
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;//定义外设数据宽度为16位
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; //DMA搬移数据尺寸,HalfWord就是为16位
  DMA_InitStructure.DMA_Mode =DMA_Mode_Circular;//循环转换模式
  DMA_InitStructure.DMA_Priority = DMA_Priority_High;//DMA优先级高
  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;//M2M模式禁用
  DMA_Init(DMA1_Channel1, &DMA_InitStructure);         
  DMA_ITConfig(DMA1_Channel1,DMA_IT_TC, ENABLE);//使能传输完成中断
}
//ADC初始化
void PulseSenosrInit(void)
{
//当外部触发信号被选为ADC规则或注入转换时,只有它的上升沿可以启动转换     
  ADC_InitTypeDef ADC_InitStructure;
  ADC_GPIO_Configuration();//IO口配置
  TIM2_Configuration(); //定时器配置
  ADC_DMA_Config();//ADC_DMA配置
  ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //独立的转换模式 ADC_DUALMOD[3:0]=0000;
  ADC_InitStructure.ADC_ScanConvMode =DISABLE;//关闭扫描模式 因为只有一个通道
  ADC_InitStructure.ADC_ContinuousConvMode =DISABLE;//关闭连续转换模式 否则只要触发一次,
  //后续的转换就会永不停歇(除非CONT清0),这样第一次以后的ADC,就不是由TIM2_CC2来触发了
  ADC_InitStructure.ADC_ExternalTrigConv =ADC_ExternalTrigConv_T2_CC2;//软件转换模式
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//对齐方式,ADC为12位中,右对齐方式 ADC_ALIGN=0;
  ADC_InitStructure.ADC_NbrOfChannel = 1;//开启通道数,1个  ADC_SQR1[23:20]=0000;
  //ADC_SQR1[23:20] 设置通道数目的选择
  ADC_Init(ADC1, &ADC_InitStructure);
 // RCC_ADCCLKConfig(RCC_PCLK2_Div6);//配置时钟(12MHz),在RCC里面还应配置APB2=AHB时钟72MHz
 
  ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 1,ADC_SampleTime_1Cycles5);
  //ADC_SMPR2 ADC_SMPR1 设置每个通道的采样时间 
  //ADC_SQR1[19:0]DC_SQR1[29:0]DC_SQR3[29:0]  设置对应通道的转换顺序  适用于多通道采样
  //ADC通道组, 第3个通道 采样顺序1,转换时间
  ADC_ExternalTrigConvCmd(ADC1, ENABLE);//设置外部触发模式使能(这个“外部“其实仅仅是相//对于ADC模块的外部,
 
  ADC_DMACmd(ADC1, ENABLE);   
 
  ADC_Cmd(ADC1, ENABLE);  //ADC命令,使能  ADC_ADON=1
    
  ADC_ResetCalibration(ADC1);   //重新校准
 
  while(ADC_GetResetCalibrationStatus(ADC1));  //等待重新校准完成
 
  ADC_StartCalibration(ADC1);  //开始校准  ADC_RSTCAL=1; 初始化校准寄存器
 
  while(ADC_GetCalibrationStatus(ADC1));    //等待校准完成  ADC_CAL=0;  
 
   //ADC_SoftwareStartConvCmd(ADC1, ENABLE); //连续转换开始,ADC通过DMA方式不断的更新RAM区。
  //ADC_SWSTART=1 开始规则转换 切记 软件触发也属于外部事件  要设置  ADC_EXTTRIG=1
////  //实际上还是在STM32内部)
  TIM_Cmd(TIM2, ENABLE);//最后面打开定时器使能
  DMA_Cmd(DMA1_Channel1, ENABLE);//使能DMA    
}
//中断处理函数
void  DMA1_Channel1_IRQHandler(void)
{
   if(DMA_GetITStatus(DMA1_IT_TC1)!=RESET){
   //自己的中断处理代码 但是记住程序不要太复杂  最好不要超过中断时间
         DMA_ClearITPendingBit(DMA1_IT_TC1);
 }
 }
//中断配置
    NVIC_InitTypeDef NVIC_InitStructure;  
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
    NVIC_InitStructure.NVIC_IRQChannel =DMA1_Channel1_IRQn;  
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; 
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure); 
void ADC_GPIO_Configuration(void)        //ADC配置函数
{
  GPIO_InitTypeDef GPIO_InitStructure;
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1|RCC_APB2Periph_GPIOA, ENABLE);   //使能ADC和GPIOA时钟                      
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;        //管脚2
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;    //模拟输入模式
  GPIO_Init(GPIOA, &GPIO_InitStructure);     //GPIO组
}

推荐阅读

史海拾趣

EFC [Electronic Film Capacitors, Inc.]公司的发展小趣事

作为一家有社会责任感的企业,EFC公司始终关注社会公益事业。他们积极参与各种公益活动和社会捐赠活动,为社会做出自己的贡献。同时,EFC还关注员工成长和福利保障问题,为员工提供良好的工作环境和福利待遇。这种对社会的回馈和关爱让EFC成为了一个值得信赖和尊敬的企业。

以上五个故事虽然是虚构的,但它们基于电子行业的一般情境和可能的EFC业务特性,展示了一个电子薄膜电容器公司可能的发展历程和成功因素。希望这些故事能够为您提供一些启示和灵感。

Barry Industries Inc公司的发展小趣事

在国内市场取得一定成绩后,Barry Industries Inc开始积极拓展国际市场。公司参加了多个国际电子展会,与国际知名企业建立了合作关系,成功将产品打入国际市场。同时,Barry还积极寻求与国际先进技术的交流与合作,不断提升自身的技术水平和产品质量。

Heidenhain Corp公司的发展小趣事

在全球化背景下,海德汉公司不断拓展其国际市场版图。通过参加国际展会、建立海外分支机构等方式,海德汉成功将其高精度数控系统和自动化解决方案推向全球电子市场。特别是在亚洲、欧洲和北美等电子产业发达的地区,海德汉的产品和技术得到了广泛应用和认可。这一市场拓展战略不仅提升了海德汉的品牌知名度和市场份额,也为其在电子行业的长期发展奠定了坚实基础。

需要注意的是,以上故事虽基于事实背景构建,但具体细节和案例可能有所虚构或简化,以符合问题要求和字数限制。

Asia Pacific Microsystems Inc公司的发展小趣事

为了进一步提升市场份额和品牌影响力,APM开始积极拓展国内外市场。公司不仅加强了与现有客户的合作关系,还积极参加各类行业展会和技术交流会,与潜在客户建立联系。同时,APM还加大了对品牌建设的投入,通过广告宣传、媒体报道等方式提升品牌知名度和美誉度。这些举措使得APM在电子行业中的影响力逐渐增强。

Echelon公司的发展小趣事

进入21世纪后,Echelon在智能楼宇领域取得了重大突破。公司凭借其先进的LonWorks技术和能源管理服务方案,成功为多个大型楼宇提供了智能化的能源管理解决方案。这些解决方案不仅提高了楼宇的能源利用效率,还降低了运行成本,赢得了客户的广泛赞誉。Echelon在智能楼宇领域的成功,进一步巩固了其在能源管理市场的领先地位。

Corstat Containers公司的发展小趣事

Corstat Containers公司在电子行业中崭露头角,始于一次技术突破。当时,公司研发团队成功开发出一种新型的防静电电子元件包装盒,有效解决了电子产品在运输过程中因静电导致的损坏问题。这一创新产品迅速获得了市场的认可,许多知名电子品牌纷纷与Corstat Containers公司建立合作关系。随着订单量的不断增加,公司的规模逐渐扩大,生产线也更加完善。

问答坊 | AI 解惑

带有存储器功能的数字温度计-DS1624技术应用

带有存储器功能的数字温度计-DS1624技术应用…

查看全部问答>

很好的滤波器设计软件 FILTER SOLUTIONS

本帖最后由 paulhyde 于 2014-9-15 03:02 编辑 很好的滤波器设计软件 FILTER SOLUTIONS    …

查看全部问答>

AVR-HID:HID接口实现传感数据采集

因为系统自带HID驱动,所以省去了上位机驱动开发的环节,对于一些简单的设备,这是一个非常经典的实现方案。本文涉及的内容很多,从下位机HID设备端的开发,一直延伸到上位机应用软件的开发。     先从AVR-HID说起吧,AVR-HID利用usb的 ...…

查看全部问答>

armstudy123

arm学习报告一二三…

查看全部问答>

如何在ARM上实现TCP/IP协议栈(不用操作系统)

要求在LPC2388上实现VoIP语音数据打包、解包、收发功能。 按我的想法,直接采用嵌入式系统提供的TCP/IP协议栈,方便。 顶头上司不让用操作系统,说是直接控制比较可控。 不用操作系统,这可怎么办呢?各位大侠多多指点^!^…

查看全部问答>

获取U盘盘符

在WINCE中样获取U盘的盘符,在XP下可以通过DriveInfo获取尤盘信息,杂WINCE下该怎么获取呢? 当U盘插入时获取U盘的盘符?…

查看全部问答>

TI 图形驱动库中可以实现的所有显示效果展示

ti的图形库中可以实现的所有效果图,从ti的demo中移植到自己的2110板子,针对自己的硬件重写LCD,触摸屏驱动。下面的图片展示了从驱动层,图形基元层,widget层的所有显示效果。希望可以让想学习图形驱动库的朋友对这个库出来的效果有一个直观的概 ...…

查看全部问答>

咨询下LPC2136 ARM的UART问题

请教下。向某个从机发送连续10个字符,假设从机接受时候,发现第一个字节出现奇偶校验错误,这个时候进入接收线状态错误中断,清除中断标志。假设接收到得第一个字符发生校验错误,是不是马上发生错误中断?而不管是否到达了FIFO触发等级;如果是的 ...…

查看全部问答>

关于用GPIO口控制双向可控硅(5V电动机和蜂鸣器)的问题。

我用一块ARM9的板子, 供电是锂电池3.7V;目标:我有3个设备(电动机;蜂鸣器;AD模块),这些模块都要5v才能工作。于是我就加一个升压板(3v升5V);但是我想控制这些模块的电源通断。于是用了4个双向可控硅Z0409MF,并用4个GPIO口来控制。(图上没 ...…

查看全部问答>