你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【说出你的故事】stm32计数器的心路历程(我要板子!!!)

[复制链接]
sun-2034138 提问时间:2016-2-16 10:28 /
最开始用st的芯片还是四五年前,想想已经过来这么久了。大学的时候掌握的第一个单片机是stm32f103zet6,现在还是记得非常清楚。分享点很久以前的吧。笔记这个东西有好多是直接网上粘来的,所以大家不要见怪。弄懂了才是真的,自己做笔记嘛~
来段套话……

STM32 的通用定时器是一个通过可编程预分频器( PSC)驱动的 16 位自动装载计数器( CNT)
构成。 STM32 的通用定时器可以被用于:测量输入信号的脉冲长度(输入捕获)或者产生输出波
形(输出比较和 PWM)等。 使用定时器预分频器和 RCC 时钟控制器预分频器,脉冲长度和波形
周期可以在几个微秒到几个毫秒间调整。 STM32 的每个通用定时器都是完全独立的,没有互相
共享的任何资源。
STM3 的通用 TIMx (TIM2、 TIM3、 TIM4 和 TIM5)定时器功能包括:
1)16 位向上、向下、向上/向下自动装载计数器( TIMx_CNT)。
2)16 位可编程(可以实时修改)预分频器(TIMx_PSC),计数器时钟频率的分频系数为 1~
65535 之间的任意数值。
3) 4 个独立通道( TIMx_CH1~4),这些通道可以用来作为:
A.输入捕获
B.输出比较
C. PWM 生成(边缘或中间对齐模式)
D.单脉冲模式输出
4)可使用外部信号( TIMx_ETR)控制定时器和定时器互连(可以用 1 个定时器控制另外
一个定时器)的同步电路。
5)如下事件发生时产生中断/DMA:
A.更新:计数器向上溢出/向下溢出,计数器初始化(通过软件或者内部/外部触发)
B.触发事件(计数器启动、停止、初始化或者由内部/外部触发计数)
C.输入捕获
D.输出比较
E.支持针对定位的增量(正交)编码器和霍尔传感器电路
F.触发输入作为外部时钟或者按周期的电流管理


[size=13.3333px]tim主要寄存器 CR1 DIER PSC 这三个寄存器是基础;
[size=13.3333px]定时器的时钟来源 内部时钟(用cube看时钟树最方便了),外部输入脚,外部触发输入,内部触发输入(用其他定时器做预分频);
[size=13.3333px]有一点值得注意的是也是很多人忽略的问题!ARR实际上是两个寄存器,他同串口的那个USART->DR的类型都是影子寄存器(类似寄存器还有几个呢)所以更新时间根据CR1的APRE位状态看是否更新,不详说看手册;
[size=13.3333px]SR寄存器看更新;
[size=13.3333px]

[size=13.3333px]pwm是我最常用的一种功能,先说说这个。要想控制pwm:
[size=13.3333px]1.看好时钟源和使能;

[size=13.3333px]2.看是否复用,如果复用开启afio看映射的对不对AFIO->MAPR;
3.设置好ARR:自动装载数值(对于初学者来说就是你打算让他一次数多少个数);
4.设置好PSC:预分频(对于初学者来说就是用内部时钟确定数一个数多久),更新的话看CR1的APRE位,不是你改了当时就更新的!!!
5.CR1:使能还有你用的到的就打钩~;
6.CCMR1/2:分为两层 每8位控制一个通道!道理和配置gpio没啥区别。简单说下吧,当时我看这个也搞了好久。
CC1S[1:0]:捕获/比较1 (方向和引脚的选择,输出的话没啥说的就是你要输出的引脚,输入的话比如映射在TL1,2或者TRC上。对于初学者的困惑可能就是TL1是啥了,这个您看通用定时器框图,芯片手册上那个大图)pwm肯定输输出。
OC1FE: 输出比较1 快速使能  ~~~~~~这个是触发输入的 ,就是看灵敏性吧。一般我都默认,还能当个防骚扰~~~~
OC1PE: 输出比较1预装载使能:随时写入TIMx_CCR1寄存器是否当即生效;
OC1M[2:0]:输出比较1模式:这个对于pwm来说只能是110或者111
OC1CE:输出比较10使能  ~~~~~~~~~~这个oc1ref在哪里呢? 捕获比较寄存器和输出控制器之间。这个东西是可以做触发另一个定时器的。什么pwm1还是2不过是电平的变化而已。
7.CCER:只有两位CCXP(我都是默认高电平有效,不知道你想咋用呢) CCXE(必须为1因为输出)
8.CCR1-4:傻子开始数数了 ~~~ (这个除ARR里面的数就是你的占空比了)
9.高级的才看BDTR寄存器呢不管你想咋设置其他为moe必须为1才能是pwm;


之后 之后就有pwm了。。。别问我为啥因为刚刚都使能了。
这样配置一遍寄存器就是新手也对这个一定有不少了解了,具体什么的功能看看手册呗~


之后分享一个双定时器同事dma触发双路adc的代码吧 想玩的朋友直接添加中断服务函数就可以了。rct6的 绝对可以用~~~

void  Adc_Init(void)
{
        NVIC_InitTypeDef NVIC_InitStructure;        
        DMA_InitTypeDef DMA_InitStructure;
        TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
        
        
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //ʱÖÓʹÄÜ
/************************************tim2*****************************************/        
        TIM_TimeBaseStructure.TIM_Period = 9999; //ÉèÖÃÔÚÏÂÒ»¸ö¸üÐÂʼþ×°Èë»î¶¯µÄ×Ô¶¯ÖØ×°ÔؼĴæÆ÷ÖÜÆÚµÄÖµ         ¼ÆÊýµ½10000Ϊ1s
        TIM_TimeBaseStructure.TIM_Prescaler =7199; //ÉèÖÃÓÃÀ´×÷ΪTIMxʱÖÓƵÂʳýÊýµÄÔ¤·ÖƵֵ  10KhzµÄ¼ÆÊýƵÂÊ  
        TIM_TimeBaseStructure.TIM_ClockDivision = 0; //ÉèÖÃʱÖÓ·Ö¸î:TDTS = Tck_tim
        TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIMÏòÉϼÆÊýģʽ
        TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //¸ù¾ÝTIM_TimeBaseInitStructÖÐÖ¸¶¨µÄ²ÎÊý³õʼ»¯TIMxµÄʱ¼ä»ùÊýµ¥Î»

        TIM_ITConfig(  //ʹÄÜ»òÕßʧÄÜÖ¸¶¨µÄTIMÖжÏ
                TIM2, //TIM2
                TIM_IT_Update ,
                DISABLE   //ʹÄÜ
                );
        NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;  //TIM3ÖжÏ
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  //ÏÈÕ¼ÓÅÏȼ¶0¼¶
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;  //´ÓÓÅÏȼ¶3¼¶
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQͨµÀ±»Ê¹ÄÜ
        NVIC_Init(&NVIC_InitStructure);  //¸ù¾ÝNVIC_InitStructÖÐÖ¸¶¨µÄ²ÎÊý³õʼ»¯ÍâÉèNVIC¼Ä´æÆ÷

        TIM_Cmd(TIM2,DISABLE);  //ʹÄÜTIMxÍâÉè
        
/************************************tim3*****************************************/        
        TIM_TimeBaseStructure.TIM_Prescaler= 7199; //100k
        TIM_TimeBaseStructure.TIM_CounterMode= TIM_CounterMode_Up;
        TIM_TimeBaseStructure.TIM_Period= 30;  //
        TIM_TimeBaseStructure.TIM_ClockDivision= 0;
        TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
        TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStructure);
        TIM_SelectOutputTrigger(TIM3,TIM_TRGOSource_Update);

        TIM_ARRPreloadConfig(TIM3,ENABLE);
        TIM_Cmd(TIM3,DISABLE);
        TIM_UpdateDisableConfig(TIM3,ENABLE);
        TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE);
        
        RCC->AHBENR  |=1<<0; // dma1
        RCC->APB2ENR |=1<<4; // GPIOC
        GPIOA->CRL |=0XFFFFF000; // PC 0 1 2 INPUT
        DMA_DeInit(DMA1_Channel1);
        DMA_InitStructure.DMA_PeripheralBaseAddr=(uint32_t)&ADC1->DR;
  DMA_InitStructure.DMA_MemoryBaseAddr=(uint32_t)ADC_buff;
  DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralSRC;
  DMA_InitStructure.DMA_BufferSize=adccnt;
  DMA_InitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Disable;
  DMA_InitStructure.DMA_MemoryInc=DMA_MemoryInc_Enable;
  DMA_InitStructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Word;
  DMA_InitStructure.DMA_MemoryDataSize=DMA_MemoryDataSize_Word ;
  DMA_InitStructure.DMA_Mode=DMA_Mode_Circular;
  DMA_InitStructure.DMA_Priority=DMA_Priority_Medium;
  DMA_InitStructure.DMA_M2M=DMA_M2M_Disable;
        DMA_Init(DMA1_Channel1,&DMA_InitStructure);
        DMA_Cmd(DMA1_Channel1,ENABLE);
        DMA_ITConfig(DMA1_Channel1,DMA_CCR1_TCIE,ENABLE); //chuanshu wancheng
        
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC |RCC_APB2Periph_ADC1|RCC_APB2Periph_ADC2|RCC_APB2Periph_ADC3,ENABLE);          //ʹÄÜADC1ͨµÀʱÖÓ

        RCC_ADCCLKConfig(RCC_PCLK2_Div6);   //ÉèÖÃADC·ÖƵÒò×Ó6 72M/6=12,ADC×î´óʱ¼ä²»Äܳ¬¹ý14M
        //mode
        
        ADC1->CR1 = 0x00060020;
        ADC1->CR2 = 0x00180100;  // 0x00180100; ->0x00080100 ÓÉÍⲿʼþÆô¶¯¸ÃΪ²»ÐèÒªÍⲿʼþÆô¶¯
        ADC_Cmd(ADC1, ENABLE);        //ʹÄÜÖ¸¶¨µÄADC1
        ADC_ResetCalibration(ADC1);        //ʹÄܸ´Î»Ð£×¼
        while(ADC_GetResetCalibrationStatus(ADC1));        //µÈ´ý¸´Î»Ð£×¼½áÊø
        ADC_StartCalibration(ADC1);         //¿ªÆôADУ׼
        while(ADC_GetCalibrationStatus(ADC1));         //µÈ´ýУ׼½áÊø
        
  ADC2->CR1 = 0x00000000;
        ADC2->CR1|= 1<<5;
        ADC2->CR2 = 0x001E0100;  
        ADC_Cmd(ADC2, ENABLE);        //ʹÄÜÖ¸¶¨µÄADC1
        ADC_ResetCalibration(ADC2);        //ʹÄܸ´Î»Ð£×¼
        while(ADC_GetResetCalibrationStatus(ADC2));        //µÈ´ý¸´Î»Ð£×¼½áÊø
        ADC_StartCalibration(ADC2);         //¿ªÆôADУ׼
        while(ADC_GetCalibrationStatus(ADC2));         //µÈ´ýУ׼½áÊø
        ADC_RegularChannelConfig(ADC1, ADC_Channel_10,1,ADC_SampleTime_55Cycles5);        //ADC1,ADCͨµÀ,²ÉÑùʱ¼äΪ239.5ÖÜÆÚ                                      
        ADC_RegularChannelConfig(ADC2, ADC_Channel_11,1,ADC_SampleTime_55Cycles5);        //ADC1,ADCͨµÀ,²ÉÑùʱ¼äΪ239.5ÖÜÆÚ                                      

        NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn; //ʹÄÜ°´¼üËùÔÚµÄÍⲿÖжÏͨµÀ
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //ÏÈÕ¼ÓÅÏȼ¶2¼¶
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; //´ÓÓÅÏȼ¶1¼¶
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //ʹÄÜÍⲿÖжÏͨµÀ
        NVIC_Init(&NVIC_InitStructure); //¸ù¾ÝNVIC_InitStructÖÐÖ¸¶¨µÄ²ÎÊý³õʼ»¯ÍâÉèNVIC¼Ä´æÆ÷        
//long i=0x 13833572189;

}

[size=13.3333px]

以下都是摘抄的笔记,好记性不如烂笔头就收藏了下来.代码能不能用我不知道 。
发布的时候字数太多发布上去了....我把连接弄来...还有好几个例程呢!
http://blog.sina.com.cn/s/blog_81e410670100wkd8.html
其实,PWM模块还可以有很多花样可以玩,比方在异常时(如CPU时钟有问题),可以紧急关闭输出,以免发生电路烧毁等严重事故。

着重补充的是有的时候你在选择管脚的时候是需要注意afio的,选择全映射还是半映射什么的,一定要看好。不然闹的根本不行不行的。
而且这个不出波形的时候是一定要查看内部寄存器的如果没有问题,那么也要多多注意你选择的周期问题!!!!!!





s

s
收藏 1 评论7 发布时间:2016-2-16 10:28

举报

7个回答
sun-2034138 回答时间:2016-2-16 10:40:06
顶顶  板板
sun-2034138 回答时间:2016-2-18 09:16:09
sun-2034138 回答时间:2016-2-18 09:19:20

WP_20151014_16_10_36_Pro.jpg
QQ图片20151209135812.jpg
lkl0305 回答时间:2016-2-18 22:41:15
支持一下
sun-2034138 回答时间:2016-2-19 10:11:03

谢喽  这个里面双路ad同时触发用的人比较少
laoyulaoyu 回答时间:2018-3-8 11:11:25
支持一下
laoyulaoyu 回答时间:2018-3-8 14:35:57
thanks

所属标签

相似问题

关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版