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

STM32学习记录(一)

[复制链接]
guoyuli 发布时间:2019-12-17 20:16
STM32产生PWM信号
1235458.png TIM模块定时器向上溢出 & 输出比较
首先我们必须肯定ST公司的实力,也承认STM32的确是一款非常不错的Cortex-M3核单片机,但是,手册实在是让人觉得无法理解,尤其是其中的TIM模块,没有条理可言,看了两天几乎还是不知所云,让人很是郁闷。同时配套的固件库的说明也很难和手册上的寄存器对应起来,研究起来非常费劲!功能强大倒是真的,但至少也应该配套一个让人看的明白的说明吧~~
两天时间研究了STM32定时器的最最基础的部分,把定时器最基础的两个功能实现了,余下的功能有待继续学习。
首先有一点需要注意:FWLib固件库目前的最新版应该是V2.0.x,V1.0.x版本固件库中,TIM1模块被独立出来,调用的函数与其他定时器不同;在V2.0系列版本中,取消了TIM1.h,所有的TIM模块统一调用TIM.h即可。网络上流传的各种代码有许多是基于v1版本的固件库,在移植到v2版本固件库时,需要做些修改。本文的所有程序都是基于V2.0固件库。
以下是定时器向上溢出示例代码:
C语言: TIM1模块产生向上溢出事件
//Step1.时钟设置:启动TIM1
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
//Step2.中断NVIC设置:允许中断,设置优先级
NVIC_InitStructure.NVIC_IRQChannel = TIM1_UP_IRQChannel;     //更新事件
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;    //抢占优先级0
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;           //响应优先级1
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;              //允许中断
NVIC_Init(&NVIC_InitStructure);                              //写入设置
//Step3.TIM1模块设置
void TIM_Configuration(void)
{
TIM_TimeBaseInitTypeDef TIM_BaseInitStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;

//TIM1 使用内部时钟
//TIM_InternalClockConfig(TIM1);
//TIM1基本设置
//设置预分频器分频系数71,即APB2=72M, TIM1_CLK=72/72=1MHz
//TIM_Period(TIM1_ARR)=1000,计数器向上计数到1000后产生更新事件,计数值归零
//向上计数模式
//TIM_RepetitionCounter(TIM1_RCR)=0,每次向上溢出都产生更新事件
TIM_BaseInitStructure.TIM_Period = 1000;
TIM_BaseInitStructure.TIM_Prescaler = 71;
TIM_BaseInitStructure.TIM_ClockDivision = 0;
TIM_BaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_BaseInitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM1, &TIM_BaseInitStructure);
//清中断,以免一启用中断后立即产生中断
TIM_ClearFlag(TIM1, TIM_FLAG_Update);
//使能TIM1中断源
TIM_ITConfig(TIM1, TIM_IT_Update, ENABLE);
//TIM1总开关:开启
TIM_Cmd(TIM1, ENABLE);
}
//Step4.中断服务子程序:
void TIM1_UP_IRQHandler(void)
{
GPIOC->ODR ^= (1<<4);                          //闪灯
TIM_ClearITPendingBit(TIM1, TIM_FLAG_Update); //清中断
}
下面是输出比较功能实现TIM1_CH1管脚输出指定频率的脉冲:
C语言: TIM1模块实现输出比较,自动翻转并触发中断
//Step1.启动TIM1,同时还要注意给相应功能管脚启动时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
//Step2. PA.8口设置为TIM1的OC1输出口
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//Step3.使能TIM1的输出比较匹配中断
NVIC_InitStructure.NVIC_IRQChannel = TIM1_CC_IRQChannel;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
//Step4. TIM模块设置
void TIM_Configuration(void)
{
     TIM_TimeBaseInitTypeDefTIM_BaseInitStructure;
     TIM_OCInitTypeDefTIM_OCInitStructure;

     //TIM1基本计数器设置
     TIM_BaseInitStructure.TIM_Period =0xffff;        //这里必须是65535
     TIM_BaseInitStructure.TIM_Prescaler= 71;        //预分频71,即72分频,得1M
    TIM_BaseInitStructure.TIM_ClockDivision = 0;     //时钟分屏
    TIM_BaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //计数模式为往上计算
    TIM_BaseInitStructure.TIM_RepetitionCounter = 0;   //重复的次数为0,也即是只计算一次
     TIM_TimeBaseInit(TIM1, &TIM_BaseInitStructure);   //写入配置
     //TIM1_OC1模块设置
     TIM_OCStructInit(&TIM_OCInitStructure);
     TIM_OCInitStructure.TIM_OCMode =TIM_OCMode_Toggle; //管脚输出模式:翻转
     TIM_OCInitStructure.TIM_Pulse =2000;        //翻转周期:2000个脉冲
     TIM_OCInitStructure.TIM_OutputState= TIM_OutputState_Enable; //使能TIM1_CH1通道
     TIM_OCInitStructure.TIM_OCPolarity =TIM_OCPolarity_High;   //输出为正逻辑
     TIM_OC1Init(TIM1,&TIM_OCInitStructure);                   //写入配置
     //清中断
     TIM_ClearFlag(TIM1, TIM_FLAG_CC1);
     //TIM1中断源设置,开启相应通道的捕捉比较中断
     TIM_ITConfig(TIM1, TIM_IT_CC1,ENABLE);
     //TIM1开启
     TIM_Cmd(TIM1, ENABLE);
     //通道输出使能
     TIM_CtrlPWMOutputs(TIM1, ENABLE);
}
Step5.中断服务子程序
void TIM1_CC_IRQHandler(void)
{
     u16 capture;
     if(TIM_GetITStatus(TIM1, TIM_IT_CC1)== SET)
     {
         TIM_ClearITPendingBit(TIM1,TIM_IT_CC1 );
         capture = TIM_GetCapture1(TIM1);
         TIM_SetCompare1(TIM1, capture +2000);
         //这里解释下:
         //将TIM1_CCR1的值增加2000,使得下一个TIM事件也需要2000个脉冲,
         //另一种方式是清零脉冲计数器
         //TIM_SetCounter(TIM2,0x0000);
     }
}
关于TIM的操作,要注意的是STM32处理器因为低功耗的需要,各模块需要分别独立开启时钟,所以,一定不要忘记给用到的模块和管脚使能时钟,因为这个原因,浪费了我好多时间阿~~!

九九的STM32笔记(二)TIM模块产生PWM
这个是STM32的PWM输出模式,STM32的TIM1模块是增强型的定时器模块,天生就是为电机控制而生,可以产生3组6路PWM,同时每组2路PWM为互补,并可以带有死区,可以用来驱动H桥。
下面的代码,是利用TIM1模块的1、2通道产生一共4路PWM的代码例子,类似代码也可以参考ST的固件库中相应example
C语言: TIM1模块产生PWM,带死区
   
//Step1.开启TIM和相应端口时钟
//启动GPIO
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | \
                       RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD,\
                        ENABLE);
//启动AFIO
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
//启动TIM1
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
//Step2. GPIO做相应设置,为AF输出
//PA.8/9口设置为TIM1的OC1输出口
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//PB.13/14口设置为TIM1_CH1N和TIM1_CH2N输出口
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
//Step3. TIM模块初始化
void TIM_Configuration(void)
{
     TIM_TimeBaseInitTypeDefTIM_BaseInitStructure;
     TIM_OCInitTypeDef TIM_OCInitStructure;
     TIM_BDTRInitTypeDefTIM_BDTRInitStructure;
     //TIM1基本计数器设置(设置PWM频率)
     //频率=TIM1_CLK/(ARR+1)
     TIM_BaseInitStructure.TIM_Period =1000-1;
     TIM_BaseInitStructure.TIM_Prescaler= 72-1;
     TIM_BaseInitStructure.TIM_ClockDivision= 0;
    TIM_BaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_BaseInitStructure.TIM_RepetitionCounter = 0;
     TIM_TimeBaseInit(TIM1,&TIM_BaseInitStructure);
     //启用ARR的影子寄存器(直到产生更新事件才更改设置)
     TIM_ARRPreloadConfig(TIM1, ENABLE);

     //TIM1_OC1模块设置(设置1通道占空比)
     TIM_OCInitStructure.TIM_OCMode =TIM_OCMode_PWM1;
     TIM_OCInitStructure.TIM_OutputState= TIM_OutputState_Enable;
     TIM_OCInitStructure.TIM_OutputNState= TIM_OutputNState_Enable;
     TIM_OCInitStructure.TIM_OCPolarity =TIM_OCPolarity_High;
     TIM_OCInitStructure.TIM_OCNPolarity= TIM_OCNPolarity_High;
     TIM_OCInitStructure.TIM_Pulse = 120;
     TIM_OC1Init(TIM1,&TIM_OCInitStructure);
     //启用CCR1寄存器的影子寄存器(直到产生更新事件才更改设置)
     TIM_OC1PreloadConfig(TIM1,TIM_OCPreload_Enable);
     //TIM2_OC2模块设置(设置2通道占空比)
     TIM_OCInitStructure.TIM_OutputState= TIM_OutputState_Enable;
     TIM_OCInitStructure.TIM_OutputNState= TIM_OutputNState_Enable;
     TIM_OCInitStructure.TIM_Pulse = 680;
     TIM_OC2Init(TIM1, &TIM_OCInitStructure);
     //启用CCR2寄存器的影子寄存器(直到产生更新事件才更改设置)
     TIM_OC2PreloadConfig(TIM1,TIM_OCPreload_Enable);
  
     //死区设置
     TIM_BDTRInitStructure.TIM_OSSRState= TIM_OSSRState_Enable;
     TIM_BDTRInitStructure.TIM_OSSIState= TIM_OSSIState_Enable;
     TIM_BDTRInitStructure.TIM_LOCKLevel= TIM_LOCKLevel_OFF;
     TIM_BDTRInitStructure.TIM_DeadTime =0x90;   //这里调整死区大小0-0xff
     TIM_BDTRInitStructure.TIM_Break =TIM_Break_Disable;
    TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_High;
    TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable;
     TIM_BDTRConfig(TIM1,&TIM_BDTRInitStructure);
  
     //TIM1开启
     TIM_Cmd(TIM1, ENABLE);
     //TIM1_OC通道输出PWM(一定要加)
     TIM_CtrlPWMOutputs(TIM1, ENABLE);
}

其实,PWM模块还可以有很多花样可以玩,比方在异常时(如CPU时钟有问题),可以紧急关闭输出,以免发生电路烧毁等严重事故。



死区,简单解释:
   通常,大功率电机、变频器等,末端都是由大功率管、IGBT等元件组成的H桥或3相桥。
每个桥的上半桥和下半桥是是绝对不能同时导通的,但高速的PWM驱动信号在达到功率元件的控制极时,往往会由于各种各样的原因产生延迟的效果,造成某个半桥元件在应该关断时没有关断,造成功率元件烧毁。
死区就是在上半桥关断后,延迟一段时间再打开下半桥或在下半桥关断后,延迟一段时间再打开上半桥,从而避免功率元件烧毁。这段延迟时间就是死区。(就是上、下半桥的元件都是关断的)死区时间控制在通常的低端单片机所配备的PWM中是没有的。


死区设置详解:


// 设置刹车特性,死区时间,锁电平,OSSI,OSSR状态和AOE(自动输出使能
  /* Automatic Output enable, Break, deadtime and lock configuration*/
  // TIM1_OSSRState设置在运行模式下非工作状态选项
  // TIM1_OSSRState_Enable,使能TIM1 OSSR状态
  // TIM1_OSSRState_Disable,失能TIM1 OSSR状态
  TIM_BDTRInitStructure.TIM_OSSRState =TIM_OSSRState_Disable;
/*
TIM1_OSSIState设置在运行模式下非工作状态选项。该参数取值见下表。
TIM1_OSSIState_Enable   使能TIM1 OSSI状态
TIM1_OSSIState_Disable  失能TIM1 OSSI状态
*/
  TIM_BDTRInitStructure.TIM_OSSIState =TIM_OSSIState_Disable;
/*
TIM1_LOCKLevel设置了锁电平参数。该参数取值见下表。
TIM1_LOCKLevel_OFF   不锁任何位
TIM1_LOCKLevel_1     使用锁电平1
TIM1_LOCKLevel_2     使用锁电平2
TIM1_LOCKLevel_3     使用锁电平3
*/
  TIM_BDTRInitStructure.TIM_LOCKLevel =TIM_LOCKLevel_1;
  // TIM1_DeadTIM1指定了输出打开和关闭状态之间的延时。
  TIM_BDTRInitStructure.TIM_DeadTime = 5;
/*
TIM1_Break使能或者失能TIM1刹车输入。该参数取值见下表。
TIM1_Break_Enable    使能TIM1刹车输入
TIM1_Break_Disable   失能TIM1刹车输入
*/
  TIM_BDTRInitStructure.TIM_Break =TIM_Break_Disable;
/*
TIM1_BreakPolarity设置TIM1刹车输入管脚极性。该参数取值见下表。
TIM1_BreakPolarity_Low    TIM1刹车输入管脚极性低
TIM1_BreakPolarity_High   TIM1刹车输入管脚极性高
*/
  TIM_BDTRInitStructure.TIM_BreakPolarity= TIM_BreakPolarity_High;
/*
TIM1_AutomaticOutput使能或者失能自动输出功能,该参数取值见下表。
TIM1_AutomaticOutput_Enable   自动输出功能使能
TIM1_AutomaticOutput_Disable  自动输出功能失能
*/
TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Disable;
  TIM_BDTRConfig(TIM1,&TIM_BDTRInitStructure);  // 这条语句可以不执行
  // 这条语句可以不执行
  TIM_SelectOutputTrigger(TIM1,TIM_TRGOSource_Update); /* Master Mode selection */
  // 这条语句可以不执行
  TIM_ARRPreloadConfig(TIM1,ENABLE);  // 使能TIMx在ARR上的预装载寄存器
  TIM_ITConfig(TIM1,TIM_IT_Update, ENABLE);
  TIM_ITConfig(TIM1,TIM_IT_CC4, ENABLE);
  TIM_Cmd(TIM1, DISABLE);







收藏 评论0 发布时间:2019-12-17 20:16

举报

0个回答

所属标签

STM32团队

意法半导体微控制器和微处理器拥有广泛的产品线,包含低成本的8位单片机和基于ARM® Cortex®-M0、M0+、M3、M4、M33、M7及A7内核并具备丰富外设选择的32位微控制器及微处理器


最新内容

相似技术帖

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