最开始用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的,选择全映射还是半映射什么的,一定要看好。不然闹的根本不行不行的。 而且这个不出波形的时候是一定要查看内部寄存器的如果没有问题,那么也要多多注意你选择的周期问题!!!!!! |
s
谢喽 这个里面双路ad同时触发用的人比较少