打印
[STM32F1]

STM32F103C8T6定时器&PWM应用编程

[复制链接]
楼主: xiaoqi000
手机看帖
扫描二维码
随时随地手机跟帖
21
xiaoqi000|  楼主 | 2024-1-29 16:42 | 只看该作者 |只看大图 回帖奖励 |倒序浏览
基本流程

计数器在时钟的每个上升沿自增,当增到0036(自动重装值)的时候,发生溢出,再来一个上升沿,计数器清零,计数器溢出,产生一个更新事件脉冲。另外还会置一个更新中断标志位UIF,这个标志位只要置1了,就会去申请中断,中断响应后,需要在中断程序中手动清零该标志位

使用特权

评论回复
22
xiaoqi000|  楼主 | 2024-1-29 16:43 | 只看该作者

使用特权

评论回复
23
xiaoqi000|  楼主 | 2024-1-29 16:43 | 只看该作者
本程序的主要内容。

调用接口 align_api.py

predict 用于生成预测结果

输入文件
输出文件
content_align

用于字段
sample_api

用于任意词

使用特权

评论回复
24
xiaoqi000|  楼主 | 2024-1-29 16:43 | 只看该作者
二、PWM
1.定义
​ 脉冲宽度调制(PWM),是英文“Pulse Width Modulation”的缩写,简称脉宽调制,是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术,广泛应用在从测量、通信到功率控制与变换的许多领域中。 ​

使用特权

评论回复
25
xiaoqi000|  楼主 | 2024-1-29 16:43 | 只看该作者
2.频率
是指1秒钟内信号从高电平到低电平再回到高电平的次数(一个周期);

也就是说一秒钟PWM有多少个周期
单位: Hz
表示方式: 50Hz 100Hz

使用特权

评论回复
26
xiaoqi000|  楼主 | 2024-1-29 16:44 | 只看该作者
3.周期
T=1/f
周期=1/频率
50Hz = 20ms 一个周期

如果频率为50Hz ,也就是说一个周期是20ms 那么一秒钟就有 50次PWM周期

使用特权

评论回复
27
xiaoqi000|  楼主 | 2024-1-29 16:44 | 只看该作者
4.占空比
是一个脉冲周期内,高电平的时间与整个周期时间的比例
单位: % (0%-100%)
表示方式:20%

使用特权

评论回复
28
xiaoqi000|  楼主 | 2024-1-29 16:44 | 只看该作者
周期: 一个脉冲信号的时间 1s内测周期次数等于频率
脉宽时间: 高电平时间

上图中 脉宽时间占总周期时间的比例,就是占空比

比方说周期的时间是10ms,脉宽时间是8ms 那么低电平时间就是2ms 总的占空比 8/(8+2)= 80%

这就是占空比为80%的脉冲信号

而我们知道PWM就是脉冲宽度调制 通过调节占空比,就可以调节脉冲宽度(脉宽时间) 而频率 就是单位时间内脉冲信号的次数,频率越大

以20Hz 占空比为80% 举例 就是1秒钟之内输出了20次脉冲信号 每次的高电平时间为40ms

使用特权

评论回复
29
xiaoqi000|  楼主 | 2024-1-29 16:44 | 只看该作者
我们换更详细点的图 上图中,周期为T
T1为高电平时间
T2 为低电平时间

假设周期T为 1s 那么频率就是 1Hz 那么高电平时间0.5s ,低电平时间0.5s 总的占空比就是 0.5 /1 =50%

使用特权

评论回复
30
xiaoqi000|  楼主 | 2024-1-29 16:44 | 只看该作者
5.原理
以单片机为例,我们知道,单片机的IO口输出的是数字信号,IO口只能输出高电平和低电平

假设高电平为5V 低电平则为0V 那么我们要输出不同的模拟电压,就要用到PWM,通过改变IO口输出的方波的占空比从而获得使用数字信号模拟成的模拟电压信号

我们知道,电压是以一种连接1或断开0的重复脉冲序列被夹到模拟负载上去的(例如LED灯,直流电机等),连接即是直流供电输出,断开即是直流供电断开。通过对连接和断开时间的控制,理论上来讲,可以输出任意不大于最大电压值(即0~5V之间任意大小)的模拟电压

比方说 占空比为50% 那就是高电平时间一半,低电平时间一半,在一定的频率下,就可以得到模拟的2.5V输出电压 那么75%的占空比 得到的电压就是3.75V

使用特权

评论回复
31
xiaoqi000|  楼主 | 2024-1-29 16:45 | 只看该作者
pwm的调节作用来源于对“占周期”的宽度控制,“占周期”变宽,输出的能量就会提高,通过阻容变换电路所得到的平均电压值也会上升,“占周期”变窄,输出的电压信号的电压平均值就会降低,通过阻容变换电路所得到的平均电压值也会下降

也就是,在一定的频率下,通过不同的占空比 即可得到不同的输出模拟电压

pwm就是通过这种原理实现D/A转换的。

使用特权

评论回复
32
xiaoqi000|  楼主 | 2024-1-29 16:45 | 只看该作者
总结:
PWM就是在合适的信号频率下,通过一个周期里改变占空比的方式来改变输出的有效电压

PWM频率越大,相应越快,

使用特权

评论回复
33
xiaoqi000|  楼主 | 2024-1-29 16:45 | 只看该作者
三、用定时器控制小灯周期性闪烁
使用STM32F103的 Tim2~Tim5其一定时器的某一个通道pin,连接一个LED,用定时器计数方式,控制LED以2s的频率周期性地亮-灭。

使用特权

评论回复
34
xiaoqi000|  楼主 | 2024-1-29 16:45 | 只看该作者
1.代码
Time.c

#include "stm32f10x.h"                  // Device header


void Timer_Init(void)
{
        //1.开启时钟,通用定时器TIM2是APB1总线的外设
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
       
        //选择时基单元的时钟为内部时钟
        TIM_InternalClockConfig(TIM2);//上电默认就是内部时钟,不写亦可以
       
        TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
        TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;//时钟分频,1分频
        TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;//计数器模式 向上计数
        TIM_TimeBaseInitStructure.TIM_Period=10000 - 1 ;//周期,ARR自动重装器的值
        TIM_TimeBaseInitStructure.TIM_Prescaler= 14400-1;//PSC预分频器的值
        //T = (PSC*ARR)/72MHz
        TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;//重复计数器的值 高级计数器使用的,这里不需要
        //2.配置时基单元
        TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);
       
        //3.使能更新中断,开启更新中断到NVIC的通路
        TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
       
        //4.NVIC优先级分组
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
        NVIC_InitTypeDef NVIC_InitStructure;
        NVIC_InitStructure.NVIC_IRQChannel=TIM2_IRQn;
        NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;//抢占优先级
        NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;//响应优先级
        NVIC_Init(&NVIC_InitStructure);
       
        //5.启动定时器
        TIM_Cmd(TIM2,ENABLE);
}

//定时器2的中断函数
void TIM2_IRQHandler(void)
{

        if(TIM_GetITStatus(TIM2,TIM_IT_Update)==SET)
        {
                GPIOA->ODR ^= GPIO_Pin_0;//把GPIO口A的第0位的输出电平取反
               
                //清除标志位
                TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
        }
               
       
}

使用特权

评论回复
35
xiaoqi000|  楼主 | 2024-1-29 16:46 | 只看该作者
Tim.h#ifndef __TIME_H
#define __TIME_H

void Timer_Init(void);

#endif

使用特权

评论回复
36
xiaoqi000|  楼主 | 2024-1-29 16:46 | 只看该作者
主函数main.c#include "stm32f10x.h"                  // Device header

#include "Delay.h"//使用延时函数

#include "OLED.h"

#include "Timer.h"


void LED0_Init()
{
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
       
        GPIO_InitTypeDef GPIO_InitStructure;
        GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
        GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;
        GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
        GPIO_Init(GPIOA,&GPIO_InitStructure);
       
//        GPIO_SetBits(GPIOA,GPIO_Pin_0);

       
}


int main(void)
{
       
//        OLED_Init();
       
        LED0_Init();

        Timer_Init();
       
        while(1)
        {
//           GPIO_ResetBits(GPIOA,GPIO_Pin_0);//亮
        };
}

使用特权

评论回复
37
xiaoqi000|  楼主 | 2024-1-29 16:47 | 只看该作者
四、PWM呼吸灯
1.代码
PWM.C

#include "stm32f10x.h"                  // Device header


//使用重映射
void PWM_Init1(void)
{
        //开启TIM2时钟,TIM2是APB1总线的外设
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
       
        //开启AFIO时钟
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
       
        //更改重映射
        GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2,ENABLE);
        GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);
       
        //选择时基单元的时钟为内部时钟
        TIM_InternalClockConfig(TIM2);
       
       
        //配置GPIO
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
        GPIO_InitTypeDef GPIO_InitStructure;
        GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;//上拉输入
        GPIO_InitStructure.GPIO_Pin=GPIO_Pin_15;
        GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
        GPIO_Init(GPIOA,&GPIO_InitStructure);
       
       
        //配置时基单元
        TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
        TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;//时钟分频
        TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;//计数器模式,向上计数
        TIM_TimeBaseInitStructure.TIM_Period=100-1;//周期,ARR自动重装器的值
        TIM_TimeBaseInitStructure.TIM_Prescaler=720-1;//PSC预分频器的值
        TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;//重复计数器的值,高级计数器使用的 这里不需要
        TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);
       
        TIM_OCInitTypeDef TIM_OCInitStructure;
        TIM_OCStructInit(&TIM_OCInitStructure);//给结构体赋初始值
        TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;//设置输出比较的模式
        TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;//设置输出比较的极性
        TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;//设置输出使能
        TIM_OCInitStructure.TIM_Pulse=0;//设置CCR
        TIM_OC1Init(TIM2,&TIM_OCInitStructure);
       
        TIM_Cmd(TIM2,ENABLE);
}


void PWM_Init(void)
{
        //开启TIM2时钟,TIM2是APB1总线的外设
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
       
        //选择时基单元的时钟为内部时钟
        TIM_InternalClockConfig(TIM2);
       
       
        //配置GPIO
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
        GPIO_InitTypeDef GPIO_InitStructure;
        GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;//上拉输入
        GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;
        GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
        GPIO_Init(GPIOA,&GPIO_InitStructure);
       
       
        //配置时基单元
        TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
        TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;//时钟分频
        TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;//计数器模式,向上计数
        TIM_TimeBaseInitStructure.TIM_Period=100-1;//周期,ARR自动重装器的值
        TIM_TimeBaseInitStructure.TIM_Prescaler=720-1;//PSC预分频器的值
        TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;//重复计数器的值,高级计数器使用的 这里不需要
        TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);
       
        TIM_OCInitTypeDef TIM_OCInitStructure;
        TIM_OCStructInit(&TIM_OCInitStructure);//给结构体赋初始值
        TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;//设置输出比较的模式
        TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;//设置输出比较的极性
        TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;//设置输出使能
        TIM_OCInitStructure.TIM_Pulse=0;//设置CCR
        TIM_OC1Init(TIM2,&TIM_OCInitStructure);
       
        TIM_Cmd(TIM2,ENABLE);
       

       
}


void PWM_SetCompare1(uint16_t Compare)
{
        TIM_SetCompare1(TIM2,Compare);//设置CCR的值
}


使用特权

评论回复
38
xiaoqi000|  楼主 | 2024-1-29 16:47 | 只看该作者
PWM.h

#ifndef __PWM_H
#define __PWM_H

void PWM_Init(void);
void PWM_SetCompare1(uint16_t Compare);
void PWM_Init1(void);

#endif

使用特权

评论回复
39
xiaoqi000|  楼主 | 2024-1-29 16:47 | 只看该作者
主函数main.c

#include "stm32f10x.h"                  // Device header

#include "Delay.h"//使用延时函数

#include "OLED.h"

#include "PWM.h"

uint8_t i;

int main(void)
{
       
        OLED_Init();
        PWM_Init();
       
       

        while(1)
        {
                for(i=0;i<=100;i++)
                {
                        //设置CCR寄存器的值
                        PWM_SetCompare1(i);
                        Delay_ms(10);
                }
               
                        for(i=0;i<=100;i++)
                {
                        PWM_SetCompare1(100-i);
                        Delay_ms(10);
                }
               
        };
}

使用特权

评论回复
40
xiaoqi000|  楼主 | 2024-1-29 16:47 | 只看该作者
2.运行效果
3.keil仿真
缩放后波形的占空比有明显的变化:

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则