最开始用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:输出比较1清0使能 ~~~~~~~~~~这个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的,选择全映射还是半映射什么的,一定要看好。不然闹的根本不行不行的。 而且这个不出波形的时候是一定要查看内部寄存器的如果没有问题,那么也要多多注意你选择的周期问题!!!!!!
|