PWM
呼吸灯显示
pwm的配置步骤:
- 使能相关时钟:RCC_AHB1PeriphClockCmd()、RCC_AHB2PeriphClockCmd()
- 配置相关的引脚模式、速度、以及复用功能:使用GPIO_InitTypeDef结构体
- 使能TIM时钟:GPIO_PinAFConfig()
- 设置分频、周期:使用TIM_TimeBaseInitTypeDef结构体
- 产生一次更新事件,更新影子寄存器的值。
- 在CCMR中设置PWM模式:使用TIM_OCInitTypeDef结构体
- 设置各通道占空比。占空比= CCRx / ARR
- 使能比较输出
- 使能预装载寄存器,使能自动重装载的预装载寄存器允许位
- 使能定时器:TIM_Cmd()
led.h、sys.h、delay.h、led.c、delay.c和之前文章里的一样就不复制过来了,可以查阅往期
main.c
#include "led.h"
#include "sys.h"
#include "delay.h"
#include "pwm.h"
int main(void)
{
unsigned int arr;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);//滴答时钟 168/8=21MHz
LED_init();
led_off();
Pwm_Init();
while(1)
{
// for(arr=0;arr<100;arr++)
// {
//
// TIM_SetCompare1(TIM13, arr);
// delay_ms(10);
// }
//
// for(arr=100;arr>0;arr--)
// {
// TIM_SetCompare1(TIM13, arr);
// delay_ms(10);
// }
for(arr=0;arr<100;arr++)
{
TIM_SetCompare1(TIM14, arr);
delay_ms(10);
}
for(arr=100;arr>0;arr--)
{
TIM_SetCompare1(TIM14, arr);
delay_ms(10);
}
for(arr=0;arr<100;arr++)
{
TIM_SetCompare3(TIM1, arr);
delay_ms(10);
}
for(arr=100;arr>0;arr--)
{
TIM_SetCompare3(TIM1, arr);
delay_ms(10);
}
for(arr=0;arr<100;arr++)
{
TIM_SetCompare4(TIM1, arr);
delay_ms(10);
}
for(arr=100;arr>0;arr--)
{
TIM_SetCompare4(TIM1, arr);
delay_ms(10);
}
}
//return 0;
}
pwm.h
#ifndef __PWM_H__
#define __PWM_H__
#include "stm32f4xx.h"
void Pwm_Init(void);
#endif
pwm.c
#include "pwm.h"
void Pwm_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_OCInitTypeDef TIM_OCInitStruct;
//
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF | RCC_AHB1Periph_GPIOE, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM13 | RCC_APB1Periph_TIM14, ENABLE);//42MHz
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9 ;//PF8 PF9
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;//复用模式
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;//推挽输出
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;//上拉
GPIO_InitStruct.GPIO_Speed = GPIO_Fast_Speed;//高速 50MHz
GPIO_Init(GPIOF,&GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14;//PE13 PE14
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;//复用模式
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;//推挽输出
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;//上拉
GPIO_InitStruct.GPIO_Speed = GPIO_Fast_Speed;//高速 50MHz
GPIO_Init(GPIOE,&GPIO_InitStruct);
//此时不做GPIO,做什么事情给指定好
//GPIO_PinAFConfig(GPIOF,GPIO_PinSource8,GPIO_AF_TIM13);
GPIO_PinAFConfig(GPIOF,GPIO_PinSource9,GPIO_AF_TIM14);
GPIO_PinAFConfig(GPIOE,GPIO_PinSource13,GPIO_AF_TIM1);
GPIO_PinAFConfig(GPIOE,GPIO_PinSource14,GPIO_AF_TIM1);
TIM_TimeBaseInitStruct.TIM_Period = 100-1;//重装载值 65535 我给5000就是500ms
TIM_TimeBaseInitStruct.TIM_Prescaler = 8400-1;//预分频器 1-65535 84MHz/8400=10000Hz--->1s
TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;//不分频了
TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;//向上计数
//TIM_TimeBaseInit(TIM13, &TIM_TimeBaseInitStruct);
TIM_TimeBaseInit(TIM14, &TIM_TimeBaseInitStruct);
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseInitStruct);
TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;//模式1
TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_Low;//低电平有效
TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;//使能
//TIM_OC1Init(TIM13, &TIM_OCInitStruct);
TIM_OC1Init(TIM14, &TIM_OCInitStruct);
TIM_OC3Init(TIM1, &TIM_OCInitStruct);
TIM_OC4Init(TIM1, &TIM_OCInitStruct);
//使能预装载寄存器
//TIM_OC1PreloadConfig(TIM13, TIM_OCPreload_Enable);
TIM_OC1PreloadConfig(TIM14, TIM_OCPreload_Enable);
TIM_OC3PreloadConfig(TIM1, TIM_OCPreload_Enable);
TIM_OC4PreloadConfig(TIM1, TIM_OCPreload_Enable);
//使能自动重装载的预装载寄存器允许位
//TIM_ARRPreloadConfig(TIM13,ENABLE);
TIM_ARRPreloadConfig(TIM14,ENABLE);
TIM_ARRPreloadConfig(TIM1,ENABLE);
TIM_CtrlPWMOutputs(TIM1,ENABLE);
//TIM_Cmd(TIM13,ENABLE);//使能定时器
TIM_Cmd(TIM14,ENABLE);
TIM_Cmd(TIM1,ENABLE);
}
串口通信
- 实现通过串口输入1打开蜂鸣器,输入0关闭蜂鸣器
- 实现通过蓝牙输入1打开蜂鸣器,输入0关闭蜂鸣器
要安装相关驱动和串口调试工具
前往GitHub下载调试工具
main.c
led.c和led.h和之前几篇文章里的一致
#include "led.h"
#include "uart.h"
int main(void)
{
LED_init(); //gpio初始化
Uart1_Init(9600);
Uart3_Init(9600);
return 0;
}
uart.h
#ifndef __UART_H__
#define __UART_H__
#include "stm32f4xx.h"
void Uart1_Init(unsigned int band);
void Uart3_Init(unsigned int band);
#endif
uart.c
#include "uart.h"
#include "sys.h"
void Uart1_Init(unsigned int band)
{
GPIO_InitTypeDef GPIO_InitStruct;
NVIC_InitTypeDef NVIC_InitStruct;
USART_InitTypeDef USART_InitStruct;
//必须先初始化时钟
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;//PA9 PA10
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;//复用模式
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;//推挽输出
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;//上拉
GPIO_InitStruct.GPIO_Speed = GPIO_Fast_Speed;//高速 50MHz
GPIO_Init(GPIOA,&GPIO_InitStruct);
//此时是往串口1复用
GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1);
GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1);
USART_InitStruct.USART_BaudRate = band;//波特率
USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件控制流
USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//数据收发
USART_InitStruct.USART_Parity = USART_Parity_No;//没有校验位
USART_InitStruct.USART_StopBits = USART_StopBits_1;//停止位1位
USART_InitStruct.USART_WordLength = USART_WordLength_8b;//数据位8位
USART_Init(USART1,&USART_InitStruct);
NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn;//UART1
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;//使能
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0x1;//抢占优先级 0-3
NVIC_InitStruct.NVIC_IRQChannelSubPriority =0x3;//响应优先级 0-3
NVIC_Init(&NVIC_InitStruct);
USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);
USART_Cmd(USART1,ENABLE);
}
void Uart3_Init(unsigned int band)
{
GPIO_InitTypeDef GPIO_InitStruct;
NVIC_InitTypeDef NVIC_InitStruct;
USART_InitTypeDef USART_InitStruct;
//必须先初始化时钟
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;//PB10 PB11
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;//复用模式
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;//推挽输出
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;//上拉
GPIO_InitStruct.GPIO_Speed = GPIO_Fast_Speed;//高速 50MHz
GPIO_Init(GPIOB,&GPIO_InitStruct);
GPIO_PinAFConfig(GPIOB,GPIO_PinSource10,GPIO_AF_USART3);
GPIO_PinAFConfig(GPIOB,GPIO_PinSource11,GPIO_AF_USART3);
USART_InitStruct.USART_BaudRate = band;//波特率
USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件控制流
USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//数据收发
USART_InitStruct.USART_Parity = USART_Parity_No;//没有校验位
USART_InitStruct.USART_StopBits = USART_StopBits_1;//停止位1位
USART_InitStruct.USART_WordLength = USART_WordLength_8b;//数据位8位
USART_Init(USART3,&USART_InitStruct);
NVIC_InitStruct.NVIC_IRQChannel = USART3_IRQn;//UART3
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;//使能
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0x1;//抢占优先级 0-3
NVIC_InitStruct.NVIC_IRQChannelSubPriority =0x3;//响应优先级 0-3
NVIC_Init(&NVIC_InitStruct);
USART_ITConfig(USART3,USART_IT_RXNE,ENABLE);
USART_Cmd(USART3,ENABLE);
}
//中断服务函数 在startup_stm32f40_41xxx.s 里面找
void USART1_IRQHandler(void)
{
char a;
//判断确实进中断
if(USART_GetITStatus(USART1,USART_IT_RXNE)==SET)
//if((USART1->SR &(0x1<<5))!=0)
{
//立马清楚中断线
USART_ClearITPendingBit(USART1,USART_IT_RXNE);
//USART1->SR &= ~(0x1<<5);
a=USART_ReceiveData(USART1);
if(a == '1')
{
PFout(8)=1;
}
if(a == '0')
{
PFout(8)=0;
}
}
}
void USART3_IRQHandler(void)
{
char b;
//判断确实进中断
if(USART_GetITStatus(USART3,USART_IT_RXNE)==SET)
//if((USART3->SR &(0x1<<5))!=0)
{
//立马清楚中断线
USART_ClearITPendingBit(USART3,USART_IT_RXNE);
//USART3->SR &= ~(0x1<<5);
b=USART_ReceiveData(USART3);
if(b == '1')
{
PFout(8)=1;
}
if(b == '0')
{
PFout(8)=0;
}
}
}
**有个地方要注意:**输入频率要一致,比如说8000000(8M),如果在.h文件不是8M就要改成一致的8M,一般情况下文件会设为只读所以直接修改不了,要文件夹找到对应文件,取消设置的只读才能修改,改完后建议重新设回只读,起保护作用。
右击后选择Open Containing Folder就可以前往该文件位置了,然后右击设置属性勾选是否只读
打开PortHelper.exe,发送1和0即可