源码:
链接: https://pan.baidu.com/s/17r1dJ3s21KfFIS3HOLDcLA?pwd=lolo 提取码: lolo 复制这段内容后打开百度网盘手机App,操作更方便哦
https://docs.qq.com/doc/DRkhDeXZ3QmJxRWVx
一、 main.c
主函数代码
int main(void)
{
SystemInit(); //系统时钟配置函数,选择外部8M晶振
Nvic_Init(); //NVIC初始化
LED_Init(); //
Key_Init();
sleep_mode();
//Timer1_Init(488,5); //16526hz
//Timer1_Init(503,5); //15870hz 拍照
//Timer1_Init(511,5); //15617hz
//Timer1_Init(483,3); //165260hz 切换摄像头
while(1)
{
GPIO_SetBits(LED_PORT ,GPIO_Pin_6);
delay_ms(250);
GPIO_ResetBits(LED_PORT ,GPIO_Pin_6);
delay_ms(250);
if(flag)
{
flag = 0;
PWR_EnterSleepMode(PWR_SLEEPEntry_WFI);
}
}
}
1. SystemInit(),是库自带的.
.知识点1:systick定时器
1.1概念:
SysTick又称滴答定时器。是一个定时设备,位于Cortex-M0内核中,和NVIC捆绑(可以产生中断信号),产生SysTick异常(IRQ异常号15)可以对输入的时钟进行计数,系统定时器一般用于操作系统,用于产生时基,维持操作系统的心跳。(1ms)。
1.2systick定时器和普通定时器(TIM)的区别:
SysTick 计数器:
①用途:用于生成系统时钟的滴答信号,从而提供精确的时间延迟和时间片管理。
适用于需要高精度延迟的应用,但功能较为简单。
②限制:
功能相对简单,主要用于基本的时间延迟和中断生成。
没有像普通定时器那样的复杂功能,例如输入捕获、输出比较、PWM 输出等。
TIM定时器
①用途:
用于更复杂的定时和计时功能,如周期性中断、PWM 信号生成、输入捕获、输出比较等。
总结: 关于两者怎么选择,如果你的应用只需要简单的周期性中断和时间延迟,SysTick 计数器可能更直接和高效。对于更复杂的应用,特别是那些需要多通道和多模式的情况,TIM 定时器会更适合。
2.Nvic_Init
void Nvic_Init(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
/*1--串口中断管理*/
//配置USART2中断
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn; //中断通道 USART2_IRQn
NVIC_InitStructure.NVIC_IRQChannelPriority = 0x00; //中断优先级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //中断使能
NVIC_Init(&NVIC_InitStructure); //调用函数进行初始化 NVIC_Init()用于配置 NVIC 的中断通道
//配置KEY1中断
NVIC_InitStructure.NVIC_IRQChannel = KEY1_BUTTON_EXTI_IRQn;//中断通道 KEY1_BUTTON_EXTI_IRQn
NVIC_InitStructure.NVIC_IRQChannelPriority = 0x03; //中断优先级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //中断使能
NVIC_Init(&NVIC_InitStructure);
// 可以继续增加,设置中断优先级
}
3.LED_Init
void LED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* GPIOE 外部时钟使能 */
RCC_AHBPeriphClockCmd(LED_PORT_CLK, ENABLE);
/* 配置 LED灯端口 外部输出上拉模式 */
GPIO_InitStructure.GPIO_Pin = LED_PIN | GPIO_Pin_6; //配置多个 GPIO 引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//设置引脚为输出模式。
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //设置输出为推挽模式。
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //启用内部上拉电阻,用于在引脚未被主动驱动时保持稳定的高电平。这样可以确保引脚在空闲或不连接的情况下不会漂浮,防止噪声干扰或未定义状态。
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置 GPIO 输出速度为 50 MHz。
GPIO_Init(LED_PORT , &GPIO_InitStructure); // 根据上述配置初始化 GPIO 端口。
//关闭LED
GPIO_ResetBits(LED_PORT ,LED_PIN_1); // 将 LED 引脚的状态设置为低电平,从而关闭 LED。
}
4.Key_Init
void Key_Init(void) //初始化两个按键(KEY1 和 KEY2)的 GPIO 引脚及其外部中断功能
{
//两个按键(KEY1 和 KEY2)的 GPIO 引脚
GPIO_InitTypeDef GPIO_InitStructure;
EXTI_InitTypeDef EXTI_InitStructure;
/* 使能KEY按键对应GPIO的Clock时钟 */
RCC_AHBPeriphClockCmd(KEY1_BUTTON_CLK , ENABLE); //使能连接到按键(KEY1)引脚的 GPIO 的时钟。
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE); //使能 SYSCFG 外设的时钟,用于配置外部中断。
//用户按键配置--KEY1--PC13
GPIO_InitStructure.GPIO_Pin = KEY1_BUTTON_PIN ; //指定要初始化的引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; //将引脚配置为输入模式。
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; //不启用上拉或下拉电阻。
GPIO_Init(KEY1_BUTTON_PORT , &GPIO_InitStructure); //将引脚配置为输入模式。
//用户按键配置--KEY2引脚配置--PC12
GPIO_InitStructure.GPIO_Pin = KEY2_BUTTON_PIN ; //指定要初始化的引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; //将引脚配置为输入模式。
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //启用上拉电阻
GPIO_Init(KEY1_BUTTON_PORT , &GPIO_InitStructure); //将引脚配置为输入模式。
//配置外部中断
SYSCFG_EXTILineConfig(KEY_BUTTON_EXTI_PORT_SOURCE, KEY1_BUTTON_EXTI_PIN_SOURCE); //配置 KEY1 的 EXTI 线源。
SYSCFG_EXTILineConfig(KEY_BUTTON_EXTI_PORT_SOURCE, KEY2_BUTTON_EXTI_PIN_SOURCE); //配置 KEY2 的 EXTI 线源。
EXTI_InitStructure.EXTI_Line = KEY1_BUTTON_EXTI_LINE; //PC13 选择外部中断线(KEY1 对应的线)。
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //设置为中断模式。
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; //设置中断触发为上升沿。
EXTI_InitStructure.EXTI_LineCmd = ENABLE; //使能该中断线。
EXTI_Init(&EXTI_InitStructure); //应用上述配置。
EXTI_InitStructure.EXTI_Line = KEY2_BUTTON_EXTI_LINE; //PC12
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
}
5.sleep_mode
void sleep_mode(void) //用于将微控制器置于低功耗模式。具体地,它使能了电源管理模块的时钟,并进入了休眠模式
{
RCC_APB1PeriphClockCmd( RCC_APB1Periph_PWR , ENABLE); //用于使能或禁用 APB1 总线上的外设时钟。在这里,它被用来使能电源管理外设的时钟 (RCC_APB1Periph_PWR),这是进入低功耗模式所必需的。ENABLE 参数表示我们要使能该外设的时钟。
PWR_EnterSleepMode(PWR_SLEEPEntry_WFI);//PWR_EnterSleepMode 函数用于将微控制器置于休眠模式。在休眠模式下,CPU 会停止执行指令,除非有外部中断或者其他唤醒事件发生。PWR_SLEEPEntry_WFI 参数指定使用 "Wait For Interrupt"(等待中断)方式进入休眠模式。即 CPU 会等待一个中断事件来唤醒。
}
配置电源管理模块(PWR)需要通过 RCC 模块进行,而 RCC 模块的配置和操作涉及到 APB1 总线,所以用到了APB1。
6.变量
unsigned short int systick_num=0x00; //systick计数器变量
unsigned short int key_num=0x00; //按键计数器变量
unsigned char Uart_buf[2]={0x00,0x00}; //缓冲接收缓冲器
unsigned char flag=0;
7. delay_ms(
void delay_ms(unsigned char a)
{
unsigned int i,j;
while(a--)
{
for(i=0;i<100;i++)
for(j=0;j<95;j++);
}
}
分析:
for(j=0;j<95;j++); 是95个指令周期
for(i=0;i<100;i++) 是100*95= 9500个指令周期
while(a--) 是9500个指令周期
因此总延迟时间为9500 * a 个指令周期
例如:假设处理器的时钟频率为16MHZ
那么每个指令周期的时间是1/16000000 = 62.5纳秒
Delay (秒) = (9500 * a) * 62.5e-9
≈ 0.00059375 * a
≈ 0.594 ms * a
在科学记数法中,e-9 是为了简化表示非常小的数值(如纳秒级别的时间)。
void sleep_mode(void) //用于将微控制器置于低功耗模式。具体地,它使能了电源管理模块的时钟,并进入了休眠模式
{
RCC_APB1PeriphClockCmd( RCC_APB1Periph_PWR , ENABLE); //用于使能或禁用 APB1 总线上的外设时钟。在这里,它被用来使能电源管理外设的时钟 (RCC_APB1Periph_PWR),这是进入低功耗模式所必需的。ENABLE 参数表示我们要使能该外设的时钟。
PWR_EnterSleepMode(PWR_SLEEPEntry_WFI);//PWR_EnterSleepMode 函数用于将微控制器置于休眠模式。在休眠模式下,CPU 会停止执行指令,除非有外部中断或者其他唤醒事件发生。PWR_SLEEPEntry_WFI 参数指定使用 "Wait For Interrupt"(等待中断)方式进入休眠模式。即 CPU 会等待一个中断事件来唤醒。
}
配置电源管理模块(PWR)需要通过 RCC 模块进行,而 RCC 模块的配置和操作涉及到 APB1 总线,所以用到了APB1。
8. Timer1_Init
void Timer1_Init(unsigned short int arr,unsigned short int psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; // 配置定时器的基本时间基准
TIM_OCInitTypeDef TIM_OCInitStructure; // 配置输出比较(OC)模式的参数
TIM_BDTRInitTypeDef TIM_BDTRInitStructure; // 配置定时器的死区时间和主从模式
PWM_GPIO_Init(); // 初始化 PWM 所用的 GPIO 端口
RCC_APB2PeriphClockCmd(F072B_TIMER_CLK , ENABLE); // 使能定时器1的时钟,以确保定时器正常工作
//TIM_DeInit(F072B_TIMER_PWM); // 可选:重置定时器设置
// 设置定时器相关参数
TIM_TimeBaseInitStructure.TIM_Prescaler = psc; // 设置定时器的预分频器值,调整定时器的计数频率
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; // 设置定时器为向上计数模式
TIM_TimeBaseInitStructure.TIM_Period = arr ; // 设置定时器的自动重装载寄存器周期值
TIM_TimeBaseInitStructure.TIM_ClockDivision = 0; // 设置时钟分频系数为 0,即不分频
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0; // 设置重复计数器的值,0 表示没有重复计数
TIM_TimeBaseInit(F072B_TIMER_PWM, &TIM_TimeBaseInitStructure); // 初始化定时器基础设置
// PWM 模式设置 - CH1
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; // 设置定时器通道为 PWM 模式 1
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; // 启用输出
TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable; // 启用互补输出
TIM_OCInitStructure.TIM_Pulse = 240; // 设置 PWM 的占空比
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; // 设置 PWM 输出的极性为低
TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCPolarity_High; // 设置互补输出的极性为高
TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set; // 设置定时器在空闲状态时输出状态
TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset; // 设置互补输出在空闲状态时的输出状态
TIM_OC1Init(F072B_TIMER_PWM, &TIM_OCInitStructure); // 初始化定时器通道 1 的输出比较设置
TIM_OC1PreloadConfig(F072B_TIMER_PWM, TIM_OCPreload_Enable); // 启用通道 1 的预装载功能
//TIM_ARRPreloadConfig(F072B_TIMER_PWM, ENABLE); // 可选:启用自动重装载预装载功能
TIM_Cmd(F072B_TIMER_PWM, ENABLE); // 启动定时器,使其开始计数
TIM_CtrlPWMOutputs(F072B_TIMER_PWM, ENABLE); // 启用定时器的 PWM 输出功能
}
8. PWM_GPIO_Init
void PWM_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure; // 声明一个 GPIO 初始化结构体变量
// 时钟配置
RCC_AHBPeriphClockCmd(F072B_PWM_CH_CLK|F072B_PWM_CHN_CLK , ENABLE); // 使能 GPIOA/GPIOB 端口的时钟
// GPIOA 通道配置 : TIM1 CH1 (PA8)/TIM1 CH2 (PA9) /TIM1 CH3 (PA10)*/
GPIO_InitStructure.GPIO_Pin = F072B_PWM_CH1_PIN|F072B_PWM_CH2_PIN|F072B_PWM_CH3_PIN; // 配置要初始化的引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; // 设置 GPIO 引脚为复用功能模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 设置引脚的速率为 50MHz
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; // 设置输出类型为推挽输出
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP ; // 设置引脚为上拉电阻
GPIO_Init(F072B_PWM_CH_P0RT , &GPIO_InitStructure); // 初始化 GPIO 端口
// GPIOB 通道配置 : TIM1 CH1N (PB13)/TIM1 CH2N (PB14) /TIM1 CH3N (PB15)*/
GPIO_InitStructure.GPIO_Pin = F072B_PWM_CH1N_PIN|F072B_PWM_CH2N_PIN|F072B_PWM_CH3N_PIN; // 配置另一组要初始化的引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; // 设置 GPIO 引脚为复用功能模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 设置引脚的速率为 50MHz
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; // 设置输出类型为推挽输出
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP ; // 设置引脚为上拉电阻
GPIO_Init(F072B_PWM_CHN_P0RT , &GPIO_InitStructure); // 初始化 GPIO 端口
// 端口复用功能配置
GPIO_PinAFConfig(F072B_PWM_CH_P0RT, F072B_PWM_CH1_SOURCE, F072B_PWM_CH1_AF); // 配置 PA8 为 TIM1 CH1 的复用功能
GPIO_PinAFConfig(F072B_PWM_CH_P0RT , F072B_PWM_CH2_SOURCE, F072B_PWM_CH2_AF); // 配置 PA9 为 TIM1 CH2 的复用功能
GPIO_PinAFConfig(F072B_PWM_CH_P0RT , F072B_PWM_CH3_SOURCE, F072B_PWM_CH3_AF); // 配置 PA10 为 TIM1 CH3 的复用功能
GPIO_PinAFConfig(F072B_PWM_CHN_P0RT , F072B_PWM_CH1N_SOURCE, F072B_PWM_CH1N_AF); // 配置 PB13 为 TIM1 CH1N 的复用功能
GPIO_PinAFConfig(F072B_PWM_CHN_P0RT , F072B_PWM_CH2N_SOURCE, F072B_PWM_CH2N_AF); // 配置 PB14 为 TIM1 CH2N 的复用功能
GPIO_PinAFConfig(F072B_PWM_CHN_P0RT , F072B_PWM_CH3N_SOURCE, F072B_PWM_CH3N_AF); // 配置 PB15 为 TIM1 CH3N 的复用功能
}
知识点2: 什么是输出比较?
输出比较(Output Compare) 是定时器的一种模式,主要用于生成精确的定时事件和脉冲。在这种模式下,定时器的计数值与预设的比较值(比较寄存器中的值)进行比较,当计数值与比较值相等时,定时器会产生一个事件或改变输出端口的状态。这通常用于生成 PWM 信号、定时中断、或控制信号的脉冲宽度。
也就是说,定时器的计数值等于比较值时,就会产生PWM信号。知识点3:分频系数和预分频值的区别?
预分频器(Prescaler):预分频器是定时器的配置参数,用于将定时器时钟的频率降低到所需的计数频率。比如,如果系统时钟为 48 MHz,通过设置预分频器为 4799,可以将计数频率降低到 10 kHz(即 48 MHz / (4799 + 1))。
时钟分频系数(Clock Division):这是一个定时器的附加参数,用于对定时器的时钟进行进一步的分频处理。在一些高级定时器中,时钟分频系数可以控制定时器内部的时钟信号的分频。通常情况下,预分频器和时钟分频系数是两个不同的配置,预分频器影响的是计数器的时钟频率,而时钟分频系数影响的是定时器的时钟源分频。
知识点4:什么是重复计数器
重复计数器 是高级定时器(例如 STM32 的高级定时器)中一个特殊的功能,用于配置定时器的重复模式。它可以用来生成重复的 PWM 信号或多个 PWM 周期。
功能:重复计数器设置了定时器在每个计数周期结束后重复执行的次数。例如,如果设置为 1,则定时器会每个计数周期重复一次。如果设置为 0,则定时器不会重复。
应用:在需要生成复杂的 PWM 波形或在高级定时器中生成多个频率不同的信号时,重复计数器非常有用。
如果重复计数器设置为2,则定时器会在每个完整周期后重复触发两次中断
知识点5:什么是 PWM 输出极性(PWM Output Polarity)?
PWM 输出极性 定义了 PWM 信号的逻辑状态,即信号的高电平和低电平的定义:
TIM_OCPolarity_Low:表示 PWM 信号的高电平对应的输出为低电平,低电平对应的输出为高电平。通常用于直接驱动负载。
TIM_OCPolarity_High:表示 PWM 信号的高电平对应的输出为高电平,低电平对应的输出为低电平。适用于需要正向驱动的应用。
知识点6: 什么是 PWM 输出空闲状态(PWM Output Idle State)?
PWM 输出空闲状态 定义了在 PWM 信号不活动时输出端口的状态:
TIM_OCIdleState_Set:在 PWM 信号为空闲状态时,将输出端口设置为设定状态(如高电平或低电平),通常用于防止在 PWM 信号停止时产生浮动信号。
TIM_OCIdleState_Reset:在 PWM 信号为空闲状态时,将输出端口设置为复位状态(通常是低电平),有助于保持信号的稳定性。