定时器----STM32最小系统板
刚刚把Echo接到了TIM1_CH1的输入端,上升沿对于时间保存到CCR1,下降沿的时间保存到了CCR2中了。当CNT的值小于CCR的值的时候,输出比较输出高电压;当CNT的值大于CCR的值的时候,会输出低电压。1us也就是10-6s,也就是1Mhz。经过预分频器PSC到10Mhz。PA0--启动测量--不少与10us的电平,不需要特别精确,只需要普通IO引脚就可以。正极性---都选择正极性,都走
一,时基单元



计数器计数脉冲,自动重装寄存器ARR设置定时的周期。
RCR设置重复计数的次数。

计数的方式:上计数,下计数,中心对齐

1us也就是10-6s,也就是1Mhz。经过预分频器PSC到10Mhz。周期ARR设置为999
假设72M,PSC设置为71----1MHz
重复计数器RCR用来设置重复计数的次数,现在要求每发生一次就溢出,RCR=0。
updata标志位
二,自制延迟函数
之前的delay函数是提供系统滴答定时器SysTick来构建的。


每1ms一次中断,中断响应函数里面currentTick++ updata标志位!!!!
#include "stm32f10x.h"
volatile uint32_t currentTick =0;//记录当前时间,单位是ms
void App_Delay(uint32_t ms);
void App_TIM3_TimeBaseInit(void);//定时器3的时基单元
void TIM3_IRQHandler(void);//中断响应函数,每1ms,updata标志位触发中断,currenttick++
void My_OnBoardLED_Init(void);
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//配置中断优先级分租2
My_OnBoardLED_Init();
App_TIM3_TimeBaseInit();
while(1)
{
GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_RESET);
App_Delay(500);
GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_SET);
App_Delay(500);
}
}
//延迟一段时间,ms:要延时的时间
void App_Delay(uint32_t ms)
{
uint32_t expireTime = currentTick + ms;//当前时间+要延迟的时间
while(currentTick < expireTime);//等待延迟的结束,每1ms都会跳转去执行中断。
}
void App_TIM3_TimeBaseInit(void)
{
// 使能定时器3的时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
// 初始化时基单元
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_TimeBaseInitStruct.TIM_Prescaler = 71;
TIM_TimeBaseInitStruct.TIM_Period = 999;
TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;//上计数
TIM_TimeBaseInitStruct.TIM_RepetitionCounter=0;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStruct);
// 使能定时器,闭合开关
TIM_Cmd(TIM3, ENABLE);
// 使能Update中断
TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);//Updata标志位
// 5. 配置NVIC内部中断
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannel = TIM3_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);
}
void TIM3_IRQHandler(void)//中断响应函数
{
if(TIM_GetFlagStatus(TIM3, TIM_FLAG_Update) == SET)//标志位有效了
{
TIM_ClearFlag(TIM3, TIM_FLAG_Update);
currentTick++;
}
}
void My_OnBoardLED_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
GPIO_InitTypeDef GPIO_InitStruct={0};
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_2MHz;
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_OD;
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_13;
GPIO_Init(GPIOC,&GPIO_InitStruct);
// 初始状态设为关闭(根据你的开发板电路决定)
GPIO_WriteBit(GPIOC, GPIO_Pin_13, Bit_SET);
}
三,输出比较
1,PWM原理

PWM--pulse width modulation 脉冲宽度调制
一种周期固定,占空比可以调节的信号。

当CNT的值小于CCR的值的时候,输出比较输出高电压;当CNT的值大于CCR的值的时候,会输出低电压。
2,八种工作模式


3,互补输出

为什么需要互补输出?

sw1和sw2打开关闭相反,也就是一对开关交替导通。
4,极性选择

根据正常输出/互补输出来选择极性。
正极性---都选择正极性,都走上面那条路,负极性,走下面带有非号的那条路
如果都选择正极性,上面正常输出,下面互补输出
四,呼吸灯实验
通过两个led,分别产生正常输出pwm和互补输出pwm。
sin范围-1-1,加一后0-2 乘0.5后0-1
占空比就等于0.5(sin(2Πt)+1)

通过调整pwm波的占空比来模拟正弦波--从而来实现呼吸灯的效果。

CH1--正常输出 CH1N互补输出 PA8和PB13

ARR决定了周期,CCR决定了占空比
#include "stm32f10x.h"
#include "delay.h"
#include "math.h"
void App_PWM_Init(void);
int main(void)
{
App_PWM_Init();
while(1)
{
float t=GetTick()*1.0e-3f;
float duty=0.5*(sin(2*3.14*t)+1);
uint16_t ccr = duty * 999; // 计算CCR值,周期×占空比得到高电平的时间 (占空比 * ARR)---比较值
TIM_SetCompare1(TIM1, ccr); // 更新PWM占空比
}
}
void App_PWM_Init(void){
// 1. 初始化GPIO为复用推挽模式(用于定时器PWM输出)
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8; // TIM1_CH1对应PA8
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_Init(GPIOA, &GPIO_InitStruct);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_13; // TIM1_CH1对应PB13
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_Init(GPIOB, &GPIO_InitStruct);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
// 2. 初始化定时器时基单元 1ms,分辨率1us
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_TimeBaseInitStruct.TIM_Prescaler = 71; // 72分频 (72MHz/72=1MHz)
TIM_TimeBaseInitStruct.TIM_Period = 999; // 计数周期1000 (ARR=999)
TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up; // 向上计数
TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0; // 不重复计数
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseInitStruct);
//配置ARR寄存器预加载
TIM_ARRPreloadConfig(TIM1,ENABLE);
//闭合开关
TIM_Cmd(TIM1,ENABLE);
// 4. 初始化输出比较通道1 (PWM模式)
TIM_OCInitTypeDef TIM_OCInitStruct;
TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1; // 八种模式选择-PWM模式1
TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High; // 正极性
TIM_OCInitStruct.TIM_OCNPolarity=TIM_OCPolarity_High; //互补输出级也是正
TIM_OCInitStruct.TIM_OutputNState=TIM_OutputNState_Enable; //互补输出及使能
TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable; // 输出使能
TIM_OCInitStruct.TIM_Pulse = 0; // CCR初始值
TIM_OC1Init(TIM1, &TIM_OCInitStruct);
//闭合MOE总开关
TIM_CtrlPWMOutputs(TIM1,ENABLE);
TIM_CCPreloadControl(TIM1,ENABLE);//开启预加载
}
五,输入捕获
1,输入捕获的基本工作原理

输入捕获了上升沿或者下降沿,向右触发ccx事件(cc1,cc2.....),会把CNT的值给到CCR,当我们读取CCR寄存器的数值的时候,其实就是输入信号变化的时间。


2,输入滤波
3,边沿检测
选择上升沿和下降沿
4,信号选择
TRC是来自从模式控制器。直接和间接
从本通道获取信号称为直接,从另外的通道获取信号称为间接

这样交叉引用的好处,省了输入通道。

5,分频
六,超声波测距实验
1,HCSR-04模块的使用方法
一眼发生一眼接收


发送超声波的时候Echo会立刻输出高电压,当接收完全部(8个周期)会输出低电压。
脉冲宽度----距离
利用定时器的输入捕获功能来测量高电平。
A8--TIM1_CH1---输入捕获
PA0--启动测量--不少与10us的电平,不需要特别精确,只需要普通IO引脚就可以。
2,思路梳理
刚刚把Echo接到了TIM1_CH1的输入端,上升沿对于时间保存到CCR1,下降沿的时间保存到了CCR2中了。


等待CC1和CC2都为1的时候,就可以了。

精度3mm,3mm/340m/s===8us。取1us完全满足要求
周期取越长越好,对于时基单元来说都是16位寄存器 0-65535。
ARR=65535,使得周期达到最大值。
3,初始化时基单元,初始化输入捕获
4,完整代码
#include "stm32f10x.h"
#include "usart.h"
#include "delay.h"
void My_USART_Init(void);
void App_HCSR04_Init(void);
int main(void)
{
My_USART_Init();
App_HCSR04_Init();
My_USART_SendString(USART1,"Hello world. \r\n");//串口没有问题
while(1)
{
// 1. 清除捕获标志位
TIM_ClearFlag(TIM1, TIM_FLAG_CC1);
TIM_ClearFlag(TIM1, TIM_FLAG_CC2);
// 2. 复位计数器
TIM_SetCounter(TIM1, 0);
TIM_GenerateEvent(TIM1, TIM_EventSource_Update);
// 3. 使能定时器
TIM_Cmd(TIM1, ENABLE);
// 4. 发送10us触发脉冲
GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_SET);
DelayUs(10); // 需要实现微秒级延时函数
GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_RESET);
// 5. 等待回波信号
while(TIM_GetFlagStatus(TIM1, TIM_FLAG_CC1) == RESET); // 等待上升沿
while(TIM_GetFlagStatus(TIM1, TIM_FLAG_CC2) == RESET); // 等待下降沿
TIM_Cmd(TIM1, DISABLE);
// 6. 计算距离(单位:米)
uint16_t t1 = TIM_GetCapture1(TIM1); // 上升沿时间
uint16_t t2 = TIM_GetCapture2(TIM1); // 下降沿时间
float distance = (t2 - t1) * 1e-6f * 340.0f / 2.0f; // 距离=(时间差×声速)/2
My_USART_Printf(USART1,"distance = %.4f\r\n",distance);
Delay(100);
}
}
void My_USART_Init(void)//三部:时钟初始化,定义结构体变量,结构体变量赋值,初始化函数,开启串口函数
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
//串口引脚的初始化
GPIO_InitTypeDef GPIO_InitStruct = {0};//**变量+变量名**
//TX PA9
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_9;
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_10MHz;
GPIO_Init(GPIOA,&GPIO_InitStruct);
//RX PA10
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_10;
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IPU;
GPIO_Init(GPIOA,&GPIO_InitStruct);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
USART_InitTypeDef USART_InitStruct={0};
USART_InitStruct.USART_BaudRate = 115200; // 波特率115200
USART_InitStruct.USART_WordLength = USART_WordLength_8b; // 8位数据
USART_InitStruct.USART_StopBits = USART_StopBits_1; // 1位停止位
USART_InitStruct.USART_Parity = USART_Parity_No; // 无校验
USART_InitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; // 双向通
USART_Init(USART1, &USART_InitStruct); // 初始化USART1
USART_Cmd(USART1, ENABLE); // 启动USART1
}
void App_HCSR04_Init(void)
{
// 初始化Trig引脚(PA0)为输出推挽模式
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_Init(GPIOA, &GPIO_InitStruct);
// 初始化Echo引脚(PA8)为输入下拉模式
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPD; // 输入下拉
GPIO_Init(GPIOA, &GPIO_InitStruct);
// 定时器时基配置
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_TimeBaseInitStruct.TIM_Prescaler = 71; // 72MHz/72=1MHz (1us分辨率)
TIM_TimeBaseInitStruct.TIM_Period = 65535; // 最大计数周期
TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseInitStruct);
TIM_ARRPreloadConfig(TIM1, ENABLE);
TIM_GenerateEvent(TIM1, TIM_EventSource_Update);
// 设置输入滤波分频
TIM_SetClockDivision(TIM1, TIM_CKD_DIV2);
// 配置输入捕获通道1(上升沿捕获)
TIM_ICInitTypeDef TIM_ICInitStruct;
TIM_ICInitStruct.TIM_Channel = TIM_Channel_1;
TIM_ICInitStruct.TIM_ICFilter = 0x08; // 滤波系数
TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Rising;
TIM_ICInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1;//直接
TIM_ICInitStruct.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM_ICInit(TIM1, &TIM_ICInitStruct);
// 配置输入捕获通道2(下降沿捕获)
TIM_ICInitStruct.TIM_Channel = TIM_Channel_2;
TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Falling;
TIM_ICInitStruct.TIM_ICSelection = TIM_ICSelection_IndirectTI;//间接
TIM_ICInit(TIM1, &TIM_ICInitStruct);
// 9. 使能捕获通道
TIM_CCxCmd(TIM1, TIM_Channel_1, TIM_CCx_Enable);
TIM_CCxCmd(TIM1, TIM_Channel_2, TIM_CCx_Enable);
}
七,从模式控制器
八,PWM参数测量原理
九,PWM参数测量实验
更多推荐



所有评论(0)