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

查看: 7754|回复: 7

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

[复制链接]

6

主题

56

回帖

0

蝴蝶豆

中级会员

最后登录
2020-7-30
发表于 2016-2-16 10:28:14 | 显示全部楼层 |阅读模式
最开始用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.触发输入作为外部时钟或者按周期的电流管理


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


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

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;

}



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

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





s

s
<
回复

使用道具 举报

6

主题

56

回帖

0

蝴蝶豆

中级会员

最后登录
2020-7-30
 楼主| 发表于 2016-2-16 10:40:06 | 显示全部楼层
顶顶  板板
回复 支持 反对

使用道具 举报

6

主题

56

回帖

0

蝴蝶豆

中级会员

最后登录
2020-7-30
 楼主| 发表于 2016-2-18 09:16:09 | 显示全部楼层
回复 支持 反对

使用道具 举报

6

主题

56

回帖

0

蝴蝶豆

中级会员

最后登录
2020-7-30
 楼主| 发表于 2016-2-18 09:19:20 | 显示全部楼层

WP_20151014_16_10_36_Pro.jpg
QQ图片20151209135812.jpg
回复 支持 反对

使用道具 举报

40

主题

1595

回帖

1

蝴蝶豆

论坛元老

最后登录
2018-7-23
发表于 2016-2-18 22:41:15 | 显示全部楼层
支持一下
回复 支持 反对

使用道具 举报

6

主题

56

回帖

0

蝴蝶豆

中级会员

最后登录
2020-7-30
 楼主| 发表于 2016-2-19 10:11:03 | 显示全部楼层

谢喽  这个里面双路ad同时触发用的人比较少
回复 支持 反对

使用道具 举报

0

主题

11

回帖

0

蝴蝶豆

新手上路

最后登录
2018-3-16
发表于 2018-3-8 11:11:25 | 显示全部楼层
支持一下
回复 支持 反对

使用道具 举报

0

主题

11

回帖

0

蝴蝶豆

新手上路

最后登录
2018-3-16
发表于 2018-3-8 14:35:57 | 显示全部楼层
thanks
回复 支持 反对

使用道具 举报

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版