STM32 ---- 再次学习STM32F103C8T6/STM32F409IGT6
目录
代码部分-----------------------------
一、环境搭建及介绍
kile4 开发51单片机(内置芯片包)、kile_v5开发STM32手动添加芯片包、如果要开发51许把51的芯片包放在kile5中 、通过注册机key来破解
对应STM芯片包
也可以通过 通过在线安装其它芯片包 ---- 可以找到GD 以及其他厂家的芯片包
STLink驱动 和CH340驱动安装
管理员运行kile5 复制CLD到注册机 破解
关于STM32基础介绍
片上资源
系统结构
启动过程
新建工程
GPIO介绍
GPIO八种模式
新建工程
电灯流程 配置RCC外设时钟
//点亮一个LED
#include "stm32f10x.h" // Device header
int main(void)
{
//APB2 包括A 和B 的IO口并配置各种时钟分频器以生成所需的时钟频率
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
//GPIO初始化类型 并配置
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
//把初始化的放进来 输出的三种写法
GPIO_Init(GPIOB,&GPIO_InitStructure);
//GPIOB拉低、拉高、在writeBit中拉高拉低
GPIO_ResetBits(GPIOB,GPIO_Pin_5);
//GPIO_SetBits(GPIOB,GPIO_Pin_5);
//GPIO_WriteBit(GPIOB,GPIO_Pin_5,Bit_RESET);
//GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal);
while(1){
}
}
外设案例
LED流水灯
#include "stm32f10x.h" // Device header
#include "Delay.h"
int main(void)
{
//APB2 包括A 和B 的IO口并配置各种时钟分频器以生成所需的时钟频率
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//也可以同时用或初始化AB
//GPIO初始化类型 并配置
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//推挽模式下 高低电平都有驱动能力点亮LED
//GPIO_Mode_Out_OD 开漏输出 低电平才有驱动能力点灯 高电平没驱动能力
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
//把初始化的放进来 输出的三种写法
GPIO_Init(GPIOA,&GPIO_InitStructure);
while(1){
GPIO_Write(GPIOA,~0x0001);//0000 0000 0000 0001 B1引脚低电平
Delay_ms(500);
GPIO_Write(GPIOA,~0x0002);//0000 0000 0000 0010
Delay_ms(500);
GPIO_Write(GPIOA,~0x0004);//0000 0000 0000 0100
Delay_ms(500);
GPIO_Write(GPIOA,~0x0008);//0000 0000 0000 1000
Delay_ms(500);
// GPIO_Write(GPIOA,~0x0010);//0000 0000 0001 0000
// Delay_ms(500);
// GPIO_Write(GPIOA,~0x0020);//0000 0000 0010 0000
// Delay_ms(500);
//
// GPIO_Write(GPIOA,~0x0040);//0000 0000 0100 0000
// Delay_ms(500);
// GPIO_Write(GPIOA,~0x0080);//0000 0000 1000 0000
// Delay_ms(500);
}
}
蜂鸣器
#include "stm32f10x.h" // Device header
#include "Delay.h"
int main(void)
{
//APB2 包括A 和B 的IO口并配置各种时钟分频器以生成所需的时钟频率
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//也可以同时用或初始化AB
//GPIO初始化类型 并配置
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//推挽模式下 高低电平都有驱动能力点亮LED
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
//把初始化的放进来 输出的三种写法
GPIO_Init(GPIOA,&GPIO_InitStructure);
while(1){
//这是因为GPIO_Write函数本身的作用是将PortVal参数的位设置为1
GPIO_Write(GPIOA,~GPIO_Pin_8);//GPIO_Write默认设置为高电平
Delay_ms(100);
GPIO_Write(GPIOA,GPIO_Pin_8);
Delay_ms(100);
GPIO_Write(GPIOA,~GPIO_Pin_8);
Delay_ms(100);
GPIO_Write(GPIOA,GPIO_Pin_8);
Delay_ms(700);
// GPIO_WriteBit(GPIOA,GPIO_Pin_8,Bit_RESET);
// Delay_ms(100);
// GPIO_WriteBit(GPIOA,GPIO_Pin_8,Bit_SET);
// Delay_ms(100);
// GPIO_WriteBit(GPIOA,GPIO_Pin_8,Bit_RESET);
// Delay_ms(100);
// GPIO_WriteBit(GPIOA,GPIO_Pin_8,Bit_SET);
// Delay_ms(700);
}
}
上拉电阻和下拉电阻知识
电压比较器
c语言基础知识 类型、结构体、枚举
类型int8_t int16_t int32_t
宏替换 #define 和typedef用法
typedef相对于更加安全
关键字:#define
用途:用一个字符串代替一个数字,便于理解,防止出错;提取程序中经常出现的参数,
便于快速修改 定义宏定义:
#define ABC 12345 引用宏定义: int a = ABC; //等效于int a = 12345;
关键字:typedef 用途:将一个比较长的变量类型名换个名字,便于使用 定义typedef: typedef unsigned char uint8_t; 引用typedef: uint8_t a; //等效于unsigned char a;
结构体两种填充方法 和 命名规则
枚举用法
关键字:enum 用途:定义一个取值受限制的整型变量,用于限制变量取值范围;宏定义的集合 定义枚举变量:
enum{FALSE = 0, TRUE = 1} EnumName; 因为枚举变量类型较长,所以通常用typedef更改变量类型名 引用枚举成员:
EnumName = FALSE; EnumName = TRUE;
常用配置
输入输出模式
GPIOMode_TypeDef
枚举类型,该枚举类型包含了多个枚举成员,表示不同的 GPIO 模式。下面是对每个成员的中文注释:
GPIO_Mode_AIN
:模拟输入模式GPIO_Mode_IN_FLOATING
:浮空输入模式GPIO_Mode_IPD
:下拉输入模式GPIO_Mode_IPU
:上拉输入模式GPIO_Mode_Out_OD
:开漏输出模式GPIO_Mode_Out_PP
:推挽输出模式GPIO_Mode_AF_OD
:复用开漏输出模式GPIO_Mode_AF_PP
:复用推挽输出模式
GPIO常用库函数
void GPIO_DeInit(GPIO_TypeDef* GPIOx)
:用于将指定GPIO端口的所有配置重置为默认值。
void GPIO_AFIODeInit(void)
:用于将AFIO(Alternate Function I/O)寄存器的配置重置为默认值。
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct)
:用于初始化指定GPIO端口的引脚配置。通过GPIO_InitStruct
结构体参数传递引脚相关配置,如引脚编号、引脚模式、引脚速度、引脚上拉/下拉等。
void GPIO_StructInit(GPIO_InitTypeDef* GPIO_InitStruct)
:用于将GPIO_InitStruct
结构体中的成员设置为默认值。
uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
:用于读取指定GPIO端口指定引脚号的输入电平(逻辑高或逻辑低)。
uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx)
:用于读取指定GPIO端口的全部输入引脚的电平状态。
uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
:用于读取指定GPIO端口指定引脚号的输出电平(逻辑高或逻辑低)。
uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx)
:用于读取指定GPIO端口的全部输出引脚的电平状态。
void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
:用于将指定GPIO端口中指定引脚置为逻辑高电平。
void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
:用于将指定GPIO端口中指定引脚置为逻辑低电平。
void GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal)
:用于设置指定GPIO端口中指定引脚的输出电平,BitVal
参数可设置为Bit_RESET
(低电平)或Bit_SET
(高电平)。
void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal)
:用于设置指定GPIO端口的全部输出引脚的电平状态。PortVal
参数是一个16位的数值,每个位对应一个引脚,可设置为逻辑低或逻辑高。
void GPIO_PinLockConfig(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
:用于锁定指定GPIO端口的指定引脚,防止意外改变其配置。
void GPIO_EventOutputConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource)
:用于配置GPIO的事件输出功能,将指定的GPIO端口和引脚映射到事件输出信号线上。
void GPIO_EventOutputCmd(FunctionalState NewState)
:用于使能或禁用GPIO的事件输出功能。
void GPIO_PinRemapConfig(uint32_t GPIO_Remap, FunctionalState NewState)
:用于重新映射GPIO端口的引脚,将其连接到其他IO端口或功能。
void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource)
:用于配置GPIO的外部中断线路,将指定的GPIO端口和引脚映射到外部中断线上。
void GPIO_ETH_MediaInterfaceConfig(uint32_t GPIO_ETH_MediaInterface)
:用于配置GPIO端口的以太网媒体接口(MII或RMII)。
中断函数
void EXTI_DeInit(void)
:用于将外部中断配置重置为默认值。
void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct)
:用于根据指定的配置参数初始化外部中断。
void EXTI_StructInit(EXTI_InitTypeDef* EXTI_InitStruct)
:用于将外部中断配置结构体EXTI_InitStruct
的成员设置为默认值。
void EXTI_GenerateSWInterrupt(uint32_t EXTI_Line)
:用于生成指定外部中断线的软件中断。可以用于模拟外部中断触发。
FlagStatus EXTI_GetFlagStatus(uint32_t EXTI_Line)
:用于获取指定外部中断线的中断标志状态。返回值为SET
(中断标志置位)或RESET
(中断标志未置位)。
void EXTI_ClearFlag(uint32_t EXTI_Line)
:用于清除指定外部中断线的中断标志。将中断标志置位。
ITStatus EXTI_GetITStatus(uint32_t EXTI_Line)
:用于获取指定外部中断线的中断状态。返回值为SET
(中断状态已触发)或RESET
(中断状态未触发)。
void EXTI_ClearITPendingBit(uint32_t EXTI_Line)
:用于清除指定外部中断线的中断挂起位。将中断挂起位复位。
模块化编程
延时函数 System
#include "stm32f10x.h"
/**
* @brief 微秒级延时
* @param xus 延时时长,范围:0~233015
* @retval 无
*/
void Delay_us(uint32_t xus)
{
SysTick->LOAD = 72 * xus; //设置定时器重装值
SysTick->VAL = 0x00; //清空当前计数值
SysTick->CTRL = 0x00000005; //设置时钟源为HCLK,启动定时器
while(!(SysTick->CTRL & 0x00010000)); //等待计数到0
SysTick->CTRL = 0x00000004; //关闭定时器
}
/**
* @brief 毫秒级延时
* @param xms 延时时长,范围:0~4294967295
* @retval 无
*/
void Delay_ms(uint32_t xms)
{
while(xms--)
{
Delay_us(1000);
}
}
/**
* @brief 秒级延时
* @param xs 延时时长,范围:0~4294967295
* @retval 无
*/
void Delay_s(uint32_t xs)
{
while(xs--)
{
Delay_ms(1000);
}
}
LED函数 Hardwore
#include "stm32f10x.h" // Device header
//LED初始化
void LED_Init(void)
{ //配置寄存器A时钟使能
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
//结构体名字 及配置
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8|GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed= GPIO_Speed_50MHz;
//配置完初始化 初始化后灯会亮
GPIO_Init(GPIOB,&GPIO_InitStructure);
//把该引脚拉高灯灭
GPIO_SetBits(GPIOB,GPIO_Pin_8|GPIO_Pin_9);
}
//LED1 开
void LED1_ON(void)
{
GPIO_ResetBits(GPIOB,GPIO_Pin_8);
}
//LED1 关
void LED1_OFF(void)
{
GPIO_SetBits(GPIOB,GPIO_Pin_8);
}
//LED2 开
void LED2_ON(void)
{
GPIO_ResetBits(GPIOB,GPIO_Pin_9);
}
//LED2 关
void LED2_OFF(void)
{
GPIO_SetBits(GPIOB,GPIO_Pin_9);
}
//LED1按键反转
void LED1_Turn(void)
{ //如果是低电平正在亮就灭 拉高
if(GPIO_ReadOutputDataBit(GPIOB,GPIO_Pin_8) == 0){
GPIO_SetBits(GPIOB,GPIO_Pin_8);
}else{//否则就是熄灭状态 就拉低 灯亮
GPIO_ResetBits(GPIOB,GPIO_Pin_8);
}
}
void LED2_Turn(void)
{ //如果是低电平正在亮就灭 拉高
if(GPIO_ReadOutputDataBit(GPIOB,GPIO_Pin_9) == 0){
GPIO_SetBits(GPIOB,GPIO_Pin_9);
}else{//否则就是熄灭状态 就拉低 灯亮
GPIO_ResetBits(GPIOB,GPIO_Pin_9);
}
}
按键函数 Hardwore
#include "stm32f10x.h" // Device header
#include "Delay.h"
//按键 初始化 PA0 PA1 设置为上拉输入
void Key_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//上拉输入 看原理图
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1;
GPIO_InitStructure.GPIO_Speed= GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
}
//获取按键值 注意返回类型uint8_t unsigned char GPIO_ReadInputDataBit读取一个位 返回0或1
uint8_t Key_getNum(void)
{
uint8_t keyNum = 0;
//如果按键1 按下 延时消抖 还是按下状态 消抖 keyNum赋值1
if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0) == 0){
Delay_ms(20);
while(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0) == 0);
Delay_ms(20);
keyNum = 1;
}
//如果按键2 按下 延时消抖 还是按下状态 消抖 keyNum赋值2
if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_1) == 0){
Delay_ms(20);
while(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_1) == 0);
Delay_ms(20);
keyNum = 2;
}
return keyNum;
}
蜂鸣器函数 Hardwore
#include "stm32f10x.h" // Device header
//蜂鸣器初始化
void Buzzer_Init(void)
{ //配置寄存器A时钟使能
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
//结构体名字 及配置
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Speed= GPIO_Speed_50MHz;
//配置完初始化 初始化后灯会亮
GPIO_Init(GPIOA,&GPIO_InitStructure);
//把该引脚拉高灯灭
//GPIO_SetBits(GPIOA,GPIO_Pin_8);
}
//蜂鸣器 开
void Buzzer_ON(void)
{
GPIO_ResetBits(GPIOA,GPIO_Pin_8);
}
//蜂鸣器 关
void Buzzer_OFF(void)
{
GPIO_SetBits(GPIOA,GPIO_Pin_8);
}
//蜂鸣器 反转
void Buzzer_Turn(void)
{ //如果是低电平正在亮就灭 拉高
if(GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_8) == 0){
GPIO_SetBits(GPIOB,GPIO_Pin_8);
}else{//否则就是熄灭状态 就拉低 灯亮
GPIO_ResetBits(GPIOA,GPIO_Pin_8);
}
}
震动模块 Hardwore
输入
#include "stm32f10x.h" // Device header
//震动模块 初始化 PA4 设置为上拉输入
void Shock_Init()
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//上拉输入 看原理图
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStructure.GPIO_Speed= GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
}
//获取震动传感器的值 有震动返回0 没有就是高
uint8_t Shock_getMsg()
{
return GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_4);
}
OLED IIC模块Hardwore
#include "stm32f10x.h"
#include "OLED_Font.h"
/*引脚配置*/
#define OLED_W_SCL(x) GPIO_WriteBit(GPIOB, GPIO_Pin_8, (BitAction)(x))
#define OLED_W_SDA(x) GPIO_WriteBit(GPIOB, GPIO_Pin_9, (BitAction)(x))
/*引脚初始化*/
void OLED_I2C_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;//开楼输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_Init(GPIOB, &GPIO_InitStructure);
OLED_W_SCL(1);
OLED_W_SDA(1);
}
/**
* @brief I2C开始
* @param 无
* @retval 无
*/
void OLED_I2C_Start(void)
{
OLED_W_SDA(1);
OLED_W_SCL(1);
OLED_W_SDA(0);
OLED_W_SCL(0);
}
/**
* @brief I2C停止
* @param 无
* @retval 无
*/
void OLED_I2C_Stop(void)
{
OLED_W_SDA(0);
OLED_W_SCL(1);
OLED_W_SDA(1);
}
/**
* @brief I2C发送一个字节
* @param Byte 要发送的一个字节
* @retval 无
*/
void OLED_I2C_SendByte(uint8_t Byte)
{
uint8_t i;
for (i = 0; i < 8; i++)
{
OLED_W_SDA(Byte & (0x80 >> i));
OLED_W_SCL(1);
OLED_W_SCL(0);
}
OLED_W_SCL(1); //额外的一个时钟,不处理应答信号
OLED_W_SCL(0);
}
/**
* @brief OLED写命令
* @param Command 要写入的命令
* @retval 无
*/
void OLED_WriteCommand(uint8_t Command)
{
OLED_I2C_Start();
OLED_I2C_SendByte(0x78); //从机地址
OLED_I2C_SendByte(0x00); //写命令
OLED_I2C_SendByte(Command);
OLED_I2C_Stop();
}
/**
* @brief OLED写数据
* @param Data 要写入的数据
* @retval 无
*/
void OLED_WriteData(uint8_t Data)
{
OLED_I2C_Start();
OLED_I2C_SendByte(0x78); //从机地址
OLED_I2C_SendByte(0x40); //写数据
OLED_I2C_SendByte(Data);
OLED_I2C_Stop();
}
/**
* @brief OLED设置光标位置
* @param Y 以左上角为原点,向下方向的坐标,范围:0~7
* @param X 以左上角为原点,向右方向的坐标,范围:0~127
* @retval 无
*/
void OLED_SetCursor(uint8_t Y, uint8_t X)
{
OLED_WriteCommand(0xB0 | Y); //设置Y位置
OLED_WriteCommand(0x10 | ((X & 0xF0) >> 4)); //设置X位置高4位
OLED_WriteCommand(0x00 | (X & 0x0F)); //设置X位置低4位
}
/**
* @brief OLED清屏
* @param 无
* @retval 无
*/
void OLED_Clear(void)
{
uint8_t i, j;
for (j = 0; j < 8; j++)
{
OLED_SetCursor(j, 0);
for(i = 0; i < 128; i++)
{
OLED_WriteData(0x00);
}
}
}
/**
* @brief OLED显示一个字符
* @param Line 行位置,范围:1~4
* @param Column 列位置,范围:1~16
* @param Char 要显示的一个字符,范围:ASCII可见字符
* @retval 无
*/
void OLED_ShowChar(uint8_t Line, uint8_t Column, char Char)
{
uint8_t i;
OLED_SetCursor((Line - 1) * 2, (Column - 1) * 8); //设置光标位置在上半部分
for (i = 0; i < 8; i++)
{
OLED_WriteData(OLED_F8x16[Char - ' '][i]); //显示上半部分内容
}
OLED_SetCursor((Line - 1) * 2 + 1, (Column - 1) * 8); //设置光标位置在下半部分
for (i = 0; i < 8; i++)
{
OLED_WriteData(OLED_F8x16[Char - ' '][i + 8]); //显示下半部分内容
}
}
/**
* @brief OLED显示字符串
* @param Line 起始行位置,范围:1~4
* @param Column 起始列位置,范围:1~16
* @param String 要显示的字符串,范围:ASCII可见字符
* @retval 无
*/
void OLED_ShowString(uint8_t Line, uint8_t Column, char *String)
{
uint8_t i;
for (i = 0; String[i] != '\0'; i++)
{
OLED_ShowChar(Line, Column + i, String[i]);
}
}
/**
* @brief OLED次方函数
* @retval 返回值等于X的Y次方
*/
uint32_t OLED_Pow(uint32_t X, uint32_t Y)
{
uint32_t Result = 1;
while (Y--)
{
Result *= X;
}
return Result;
}
/**
* @brief OLED显示数字(十进制,正数)
* @param Line 起始行位置,范围:1~4
* @param Column 起始列位置,范围:1~16
* @param Number 要显示的数字,范围:0~4294967295
* @param Length 要显示数字的长度,范围:1~10
* @retval 无
*/
void OLED_ShowNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
{
uint8_t i;
for (i = 0; i < Length; i++)
{
OLED_ShowChar(Line, Column + i, Number / OLED_Pow(10, Length - i - 1) % 10 + '0');
}
}
/**
* @brief OLED显示数字(十进制,带符号数)
* @param Line 起始行位置,范围:1~4
* @param Column 起始列位置,范围:1~16
* @param Number 要显示的数字,范围:-2147483648~2147483647
* @param Length 要显示数字的长度,范围:1~10
* @retval 无
*/
void OLED_ShowSignedNum(uint8_t Line, uint8_t Column, int32_t Number, uint8_t Length)
{
uint8_t i;
uint32_t Number1;
if (Number >= 0)
{
OLED_ShowChar(Line, Column, '+');
Number1 = Number;
}
else
{
OLED_ShowChar(Line, Column, '-');
Number1 = -Number;
}
for (i = 0; i < Length; i++)
{
OLED_ShowChar(Line, Column + i + 1, Number1 / OLED_Pow(10, Length - i - 1) % 10 + '0');
}
}
/**
* @brief OLED显示数字(十六进制,正数)
* @param Line 起始行位置,范围:1~4
* @param Column 起始列位置,范围:1~16
* @param Number 要显示的数字,范围:0~0xFFFFFFFF
* @param Length 要显示数字的长度,范围:1~8
* @retval 无
*/
void OLED_ShowHexNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
{
uint8_t i, SingleNumber;
for (i = 0; i < Length; i++)
{
SingleNumber = Number / OLED_Pow(16, Length - i - 1) % 16;
if (SingleNumber < 10)
{
OLED_ShowChar(Line, Column + i, SingleNumber + '0');
}
else
{
OLED_ShowChar(Line, Column + i, SingleNumber - 10 + 'A');
}
}
}
/**
* @brief OLED显示数字(二进制,正数)
* @param Line 起始行位置,范围:1~4
* @param Column 起始列位置,范围:1~16
* @param Number 要显示的数字,范围:0~1111 1111 1111 1111
* @param Length 要显示数字的长度,范围:1~16
* @retval 无
*/
void OLED_ShowBinNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
{
uint8_t i;
for (i = 0; i < Length; i++)
{
OLED_ShowChar(Line, Column + i, Number / OLED_Pow(2, Length - i - 1) % 2 + '0');
}
}
/**
* @brief OLED初始化
* @param 无
* @retval 无
*/
void OLED_Init(void)
{
uint32_t i, j;
for (i = 0; i < 1000; i++) //上电延时
{
for (j = 0; j < 1000; j++);
}
OLED_I2C_Init(); //端口初始化
OLED_WriteCommand(0xAE); //关闭显示
OLED_WriteCommand(0xD5); //设置显示时钟分频比/振荡器频率
OLED_WriteCommand(0x80);
OLED_WriteCommand(0xA8); //设置多路复用率
OLED_WriteCommand(0x3F);
OLED_WriteCommand(0xD3); //设置显示偏移
OLED_WriteCommand(0x00);
OLED_WriteCommand(0x40); //设置显示开始行
OLED_WriteCommand(0xA1); //设置左右方向,0xA1正常 0xA0左右反置
OLED_WriteCommand(0xC8); //设置上下方向,0xC8正常 0xC0上下反置
OLED_WriteCommand(0xDA); //设置COM引脚硬件配置
OLED_WriteCommand(0x12);
OLED_WriteCommand(0x81); //设置对比度控制
OLED_WriteCommand(0xCF);
OLED_WriteCommand(0xD9); //设置预充电周期
OLED_WriteCommand(0xF1);
OLED_WriteCommand(0xDB); //设置VCOMH取消选择级别
OLED_WriteCommand(0x30);
OLED_WriteCommand(0xA4); //设置整个显示打开/关闭
OLED_WriteCommand(0xA6); //设置正常/倒转显示
OLED_WriteCommand(0x8D); //设置充电泵
OLED_WriteCommand(0x14);
OLED_WriteCommand(0xAF); //开启显示
OLED_Clear(); //OLED清屏
}
字库
#ifndef __OLED_FONT_H
#define __OLED_FONT_H
/*OLED字模库,宽8像素,高16像素*/
const uint8_t OLED_F8x16[][16]=
{
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,// 0
0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x33,0x30,0x00,0x00,0x00,//! 1
0x00,0x10,0x0C,0x06,0x10,0x0C,0x06,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//" 2
0x40,0xC0,0x78,0x40,0xC0,0x78,0x40,0x00,
0x04,0x3F,0x04,0x04,0x3F,0x04,0x04,0x00,//# 3
0x00,0x70,0x88,0xFC,0x08,0x30,0x00,0x00,
0x00,0x18,0x20,0xFF,0x21,0x1E,0x00,0x00,//$ 4
0xF0,0x08,0xF0,0x00,0xE0,0x18,0x00,0x00,
0x00,0x21,0x1C,0x03,0x1E,0x21,0x1E,0x00,//% 5
0x00,0xF0,0x08,0x88,0x70,0x00,0x00,0x00,
0x1E,0x21,0x23,0x24,0x19,0x27,0x21,0x10,//& 6
0x10,0x16,0x0E,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//' 7
0x00,0x00,0x00,0xE0,0x18,0x04,0x02,0x00,
0x00,0x00,0x00,0x07,0x18,0x20,0x40,0x00,//( 8
0x00,0x02,0x04,0x18,0xE0,0x00,0x00,0x00,
0x00,0x40,0x20,0x18,0x07,0x00,0x00,0x00,//) 9
0x40,0x40,0x80,0xF0,0x80,0x40,0x40,0x00,
0x02,0x02,0x01,0x0F,0x01,0x02,0x02,0x00,//* 10
0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0x00,
0x01,0x01,0x01,0x1F,0x01,0x01,0x01,0x00,//+ 11
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x80,0xB0,0x70,0x00,0x00,0x00,0x00,0x00,//, 12
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x01,//- 13
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x30,0x30,0x00,0x00,0x00,0x00,0x00,//. 14
0x00,0x00,0x00,0x00,0x80,0x60,0x18,0x04,
0x00,0x60,0x18,0x06,0x01,0x00,0x00,0x00,/// 15
0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,
0x00,0x0F,0x10,0x20,0x20,0x10,0x0F,0x00,//0 16
0x00,0x10,0x10,0xF8,0x00,0x00,0x00,0x00,
0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//1 17
0x00,0x70,0x08,0x08,0x08,0x88,0x70,0x00,
0x00,0x30,0x28,0x24,0x22,0x21,0x30,0x00,//2 18
0x00,0x30,0x08,0x88,0x88,0x48,0x30,0x00,
0x00,0x18,0x20,0x20,0x20,0x11,0x0E,0x00,//3 19
0x00,0x00,0xC0,0x20,0x10,0xF8,0x00,0x00,
0x00,0x07,0x04,0x24,0x24,0x3F,0x24,0x00,//4 20
0x00,0xF8,0x08,0x88,0x88,0x08,0x08,0x00,
0x00,0x19,0x21,0x20,0x20,0x11,0x0E,0x00,//5 21
0x00,0xE0,0x10,0x88,0x88,0x18,0x00,0x00,
0x00,0x0F,0x11,0x20,0x20,0x11,0x0E,0x00,//6 22
0x00,0x38,0x08,0x08,0xC8,0x38,0x08,0x00,
0x00,0x00,0x00,0x3F,0x00,0x00,0x00,0x00,//7 23
0x00,0x70,0x88,0x08,0x08,0x88,0x70,0x00,
0x00,0x1C,0x22,0x21,0x21,0x22,0x1C,0x00,//8 24
0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,
0x00,0x00,0x31,0x22,0x22,0x11,0x0F,0x00,//9 25
0x00,0x00,0x00,0xC0,0xC0,0x00,0x00,0x00,
0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00,//: 26
0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,
0x00,0x00,0x80,0x60,0x00,0x00,0x00,0x00,//; 27
0x00,0x00,0x80,0x40,0x20,0x10,0x08,0x00,
0x00,0x01,0x02,0x04,0x08,0x10,0x20,0x00,//< 28
0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x00,
0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x00,//= 29
0x00,0x08,0x10,0x20,0x40,0x80,0x00,0x00,
0x00,0x20,0x10,0x08,0x04,0x02,0x01,0x00,//> 30
0x00,0x70,0x48,0x08,0x08,0x08,0xF0,0x00,
0x00,0x00,0x00,0x30,0x36,0x01,0x00,0x00,//? 31
0xC0,0x30,0xC8,0x28,0xE8,0x10,0xE0,0x00,
0x07,0x18,0x27,0x24,0x23,0x14,0x0B,0x00,//@ 32
0x00,0x00,0xC0,0x38,0xE0,0x00,0x00,0x00,
0x20,0x3C,0x23,0x02,0x02,0x27,0x38,0x20,//A 33
0x08,0xF8,0x88,0x88,0x88,0x70,0x00,0x00,
0x20,0x3F,0x20,0x20,0x20,0x11,0x0E,0x00,//B 34
0xC0,0x30,0x08,0x08,0x08,0x08,0x38,0x00,
0x07,0x18,0x20,0x20,0x20,0x10,0x08,0x00,//C 35
0x08,0xF8,0x08,0x08,0x08,0x10,0xE0,0x00,
0x20,0x3F,0x20,0x20,0x20,0x10,0x0F,0x00,//D 36
0x08,0xF8,0x88,0x88,0xE8,0x08,0x10,0x00,
0x20,0x3F,0x20,0x20,0x23,0x20,0x18,0x00,//E 37
0x08,0xF8,0x88,0x88,0xE8,0x08,0x10,0x00,
0x20,0x3F,0x20,0x00,0x03,0x00,0x00,0x00,//F 38
0xC0,0x30,0x08,0x08,0x08,0x38,0x00,0x00,
0x07,0x18,0x20,0x20,0x22,0x1E,0x02,0x00,//G 39
0x08,0xF8,0x08,0x00,0x00,0x08,0xF8,0x08,
0x20,0x3F,0x21,0x01,0x01,0x21,0x3F,0x20,//H 40
0x00,0x08,0x08,0xF8,0x08,0x08,0x00,0x00,
0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//I 41
0x00,0x00,0x08,0x08,0xF8,0x08,0x08,0x00,
0xC0,0x80,0x80,0x80,0x7F,0x00,0x00,0x00,//J 42
0x08,0xF8,0x88,0xC0,0x28,0x18,0x08,0x00,
0x20,0x3F,0x20,0x01,0x26,0x38,0x20,0x00,//K 43
0x08,0xF8,0x08,0x00,0x00,0x00,0x00,0x00,
0x20,0x3F,0x20,0x20,0x20,0x20,0x30,0x00,//L 44
0x08,0xF8,0xF8,0x00,0xF8,0xF8,0x08,0x00,
0x20,0x3F,0x00,0x3F,0x00,0x3F,0x20,0x00,//M 45
0x08,0xF8,0x30,0xC0,0x00,0x08,0xF8,0x08,
0x20,0x3F,0x20,0x00,0x07,0x18,0x3F,0x00,//N 46
0xE0,0x10,0x08,0x08,0x08,0x10,0xE0,0x00,
0x0F,0x10,0x20,0x20,0x20,0x10,0x0F,0x00,//O 47
0x08,0xF8,0x08,0x08,0x08,0x08,0xF0,0x00,
0x20,0x3F,0x21,0x01,0x01,0x01,0x00,0x00,//P 48
0xE0,0x10,0x08,0x08,0x08,0x10,0xE0,0x00,
0x0F,0x18,0x24,0x24,0x38,0x50,0x4F,0x00,//Q 49
0x08,0xF8,0x88,0x88,0x88,0x88,0x70,0x00,
0x20,0x3F,0x20,0x00,0x03,0x0C,0x30,0x20,//R 50
0x00,0x70,0x88,0x08,0x08,0x08,0x38,0x00,
0x00,0x38,0x20,0x21,0x21,0x22,0x1C,0x00,//S 51
0x18,0x08,0x08,0xF8,0x08,0x08,0x18,0x00,
0x00,0x00,0x20,0x3F,0x20,0x00,0x00,0x00,//T 52
0x08,0xF8,0x08,0x00,0x00,0x08,0xF8,0x08,
0x00,0x1F,0x20,0x20,0x20,0x20,0x1F,0x00,//U 53
0x08,0x78,0x88,0x00,0x00,0xC8,0x38,0x08,
0x00,0x00,0x07,0x38,0x0E,0x01,0x00,0x00,//V 54
0xF8,0x08,0x00,0xF8,0x00,0x08,0xF8,0x00,
0x03,0x3C,0x07,0x00,0x07,0x3C,0x03,0x00,//W 55
0x08,0x18,0x68,0x80,0x80,0x68,0x18,0x08,
0x20,0x30,0x2C,0x03,0x03,0x2C,0x30,0x20,//X 56
0x08,0x38,0xC8,0x00,0xC8,0x38,0x08,0x00,
0x00,0x00,0x20,0x3F,0x20,0x00,0x00,0x00,//Y 57
0x10,0x08,0x08,0x08,0xC8,0x38,0x08,0x00,
0x20,0x38,0x26,0x21,0x20,0x20,0x18,0x00,//Z 58
0x00,0x00,0x00,0xFE,0x02,0x02,0x02,0x00,
0x00,0x00,0x00,0x7F,0x40,0x40,0x40,0x00,//[ 59
0x00,0x0C,0x30,0xC0,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x01,0x06,0x38,0xC0,0x00,//\ 60
0x00,0x02,0x02,0x02,0xFE,0x00,0x00,0x00,
0x00,0x40,0x40,0x40,0x7F,0x00,0x00,0x00,//] 61
0x00,0x00,0x04,0x02,0x02,0x02,0x04,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//^ 62
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,//_ 63
0x00,0x02,0x02,0x04,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//` 64
0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,
0x00,0x19,0x24,0x22,0x22,0x22,0x3F,0x20,//a 65
0x08,0xF8,0x00,0x80,0x80,0x00,0x00,0x00,
0x00,0x3F,0x11,0x20,0x20,0x11,0x0E,0x00,//b 66
0x00,0x00,0x00,0x80,0x80,0x80,0x00,0x00,
0x00,0x0E,0x11,0x20,0x20,0x20,0x11,0x00,//c 67
0x00,0x00,0x00,0x80,0x80,0x88,0xF8,0x00,
0x00,0x0E,0x11,0x20,0x20,0x10,0x3F,0x20,//d 68
0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,
0x00,0x1F,0x22,0x22,0x22,0x22,0x13,0x00,//e 69
0x00,0x80,0x80,0xF0,0x88,0x88,0x88,0x18,
0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//f 70
0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x00,
0x00,0x6B,0x94,0x94,0x94,0x93,0x60,0x00,//g 71
0x08,0xF8,0x00,0x80,0x80,0x80,0x00,0x00,
0x20,0x3F,0x21,0x00,0x00,0x20,0x3F,0x20,//h 72
0x00,0x80,0x98,0x98,0x00,0x00,0x00,0x00,
0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//i 73
0x00,0x00,0x00,0x80,0x98,0x98,0x00,0x00,
0x00,0xC0,0x80,0x80,0x80,0x7F,0x00,0x00,//j 74
0x08,0xF8,0x00,0x00,0x80,0x80,0x80,0x00,
0x20,0x3F,0x24,0x02,0x2D,0x30,0x20,0x00,//k 75
0x00,0x08,0x08,0xF8,0x00,0x00,0x00,0x00,
0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//l 76
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x00,
0x20,0x3F,0x20,0x00,0x3F,0x20,0x00,0x3F,//m 77
0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x00,
0x20,0x3F,0x21,0x00,0x00,0x20,0x3F,0x20,//n 78
0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,
0x00,0x1F,0x20,0x20,0x20,0x20,0x1F,0x00,//o 79
0x80,0x80,0x00,0x80,0x80,0x00,0x00,0x00,
0x80,0xFF,0xA1,0x20,0x20,0x11,0x0E,0x00,//p 80
0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x00,
0x00,0x0E,0x11,0x20,0x20,0xA0,0xFF,0x80,//q 81
0x80,0x80,0x80,0x00,0x80,0x80,0x80,0x00,
0x20,0x20,0x3F,0x21,0x20,0x00,0x01,0x00,//r 82
0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x00,
0x00,0x33,0x24,0x24,0x24,0x24,0x19,0x00,//s 83
0x00,0x80,0x80,0xE0,0x80,0x80,0x00,0x00,
0x00,0x00,0x00,0x1F,0x20,0x20,0x00,0x00,//t 84
0x80,0x80,0x00,0x00,0x00,0x80,0x80,0x00,
0x00,0x1F,0x20,0x20,0x20,0x10,0x3F,0x20,//u 85
0x80,0x80,0x80,0x00,0x00,0x80,0x80,0x80,
0x00,0x01,0x0E,0x30,0x08,0x06,0x01,0x00,//v 86
0x80,0x80,0x00,0x80,0x00,0x80,0x80,0x80,
0x0F,0x30,0x0C,0x03,0x0C,0x30,0x0F,0x00,//w 87
0x00,0x80,0x80,0x00,0x80,0x80,0x80,0x00,
0x00,0x20,0x31,0x2E,0x0E,0x31,0x20,0x00,//x 88
0x80,0x80,0x80,0x00,0x00,0x80,0x80,0x80,
0x80,0x81,0x8E,0x70,0x18,0x06,0x01,0x00,//y 89
0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x00,
0x00,0x21,0x30,0x2C,0x22,0x21,0x30,0x00,//z 90
0x00,0x00,0x00,0x00,0x80,0x7C,0x02,0x02,
0x00,0x00,0x00,0x00,0x00,0x3F,0x40,0x40,//{ 91
0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,//| 92
0x00,0x02,0x02,0x7C,0x80,0x00,0x00,0x00,
0x00,0x40,0x40,0x3F,0x00,0x00,0x00,0x00,//} 93
0x00,0x06,0x01,0x01,0x02,0x02,0x04,0x04,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//~ 94
};
#endif
调试方法
串口打印 、oled、 电灯、kile调试 通过各种现象调试
kile点击放大镜调试、板子实时在跑,若要修改函数则需要先停止调试功能
中断系统
概念:
中断:在主程序运行过程中,出现了特定的中断触发条件(中断源),使得CPU暂停当前正在运行的程序,转而去处理中断程序,处理完成后又返回原来被暂停的位置继续运行
中断优先级:当有多个中断源同时申请中断时,CPU会根据中断源的轻重缓急进行裁决,优先响应更加紧急的中断源
中断嵌套:当一个中断程序正在运行时,又有新的更高优先级的中断源申请中断,CPU再次暂停当前中断程序,转而去处理新的中断程序,处理完成后依次进行返回
NVIC中断控制寄存器结构
NVIC分组 抢占优先级和响应优先级
中断配置 --代码-----------------
中断 oled刷新count的值
触发中断和触发事件 触发事件不会经过cpu直接反应事件
#include "stm32f10x.h" // Device header
uint16_t CountSensor_count;
void CountSensor_Init(void)
{
//RCC 时钟配置
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
//GPIO初始化配置
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStructure);
//AFIO初始化配置 GPIO引脚到外部中断线的映射配置
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource14);
//EXTI初始化配置
EXTI_InitTypeDef EXTI_InitStructure;
EXTI_InitStructure.EXTI_Line = EXTI_Line14;//中断线14
EXTI_InitStructure.EXTI_LineCmd= ENABLE;//使能
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//中断 另一个是事件
EXTI_InitStructure.EXTI_Trigger= EXTI_Trigger_Falling;//触发方式 上升沿 下降沿 上升下降沿都出触发
EXTI_Init(&EXTI_InitStructure);//指定GPIO端口和引脚映射到外部中断线上
//配置NVIC
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//用于配置中断优先级分组。中断优先级分组决定了中断优先级的划分方式
NVIC_InitTypeDef NVIC_InitStructure; //结构体配置
NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;//指定中断线
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;//响应中断优先级 0-14
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;//抢占中断优先级 0-14
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//开启
NVIC_Init(&NVIC_InitStructure);//初始化中断控制寄存器
}
//返回count的值
uint16_t CountSensor_Get(void)
{
return CountSensor_count;
}
//10-15的中断处理函数 当发生中断就跳转到该函数 后要清楚中断标志位
void EXTI15_10_IRQHandler(void)
{ //检测是不是14引脚触发中断 SET触发中断
if(EXTI_GetITStatus(EXTI_Line14) == SET){//读取该引脚电平是否拉低 0 是count++
if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_14) == Bit_RESET){
CountSensor_count++;
}
EXTI_ClearITPendingBit(EXTI_Line14);
}
}
/*
按键中断电灯
*/
#include "stm32f10x.h" // Device header
#include "LED.h"
void CountSensor_Init(void)
{
//rcc 设置PPIOA时钟和复用口时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
//gpio afio配置GPIO和映射到复用口
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1;
GPIO_InitStructure.GPIO_Speed= GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource1);
//exti配置exti中断
EXTI_InitTypeDef EXTI_InitStructure;
EXTI_InitStructure.EXTI_Line = EXTI_Line0|EXTI_Line1;//中断映射pin
EXTI_InitStructure.EXTI_LineCmd = ENABLE;//使能开启中断
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//产生中断 还是事件
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;//下降延触发
EXTI_Init(&EXTI_InitStructure);
//NVIC_Prior 中断分组 5组 0 1 2(0-3抢占 0-3响应) 3 4
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
//nvic分组后初始化配置 两个角可以共用一个结构体
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;//中断向量
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;//抢占优先级 -- 根据分来来填写
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;//响应优先级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//
NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;//中断向量
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;//抢占优先级 -- 根据分来来填写
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;//响应优先级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//
NVIC_Init(&NVIC_InitStructure);
}
//引脚0外部中断
void EXTI0_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line0) == SET){ //检测0是否按下
LED1_ON(); //开灯
EXTI_ClearITPendingBit(EXTI_Line0);//清除标志位
}
}
//引脚1外部中断
void EXTI1_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line1) == SET){//检测0是否按下
LED1_OFF(); //关灯
EXTI_ClearITPendingBit(EXTI_Line1);//清除标志位
}
}
#include "stm32f10x.h" // Device header
#include "Shock.h"
#include "Buzzer.h"
#include "Delay.h"
#include "OLED.h"
#include "CountSensor.h"
int main(void)
{
OLED_Init();
CountSensor_Init();
OLED_ShowString(1, 1, "Count:");
while (1)
{
OLED_ShowNum(1, 7, CountSensor_Get(),5);
}
}
两个中断时
#include "stm32f10x.h" // Device header
int16_t Encoder_Count;
void Encoder_Init(void)
{
//RCC 时钟配置
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
//GPIO初始化配置
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1;//初始化引脚0 和 1
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStructure);
//AFIO初始化配置 GPIO引脚到外部中断线的映射配置
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource0);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource1);
//EXTI初始化配置
EXTI_InitTypeDef EXTI_InitStructure;
EXTI_InitStructure.EXTI_Line = EXTI_Line0|EXTI_Line1;//中断线0 1映射
EXTI_InitStructure.EXTI_LineCmd= ENABLE;//使能
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//中断 另一个是事件
EXTI_InitStructure.EXTI_Trigger= EXTI_Trigger_Falling;//触发方式 上升沿 下降沿 上升下降沿都出触发
EXTI_Init(&EXTI_InitStructure);//指定GPIO端口和引脚映射到外部中断线上
//配置NVIC
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//用于配置中断优先级分组。中断优先级分组决定了中断优先级的划分方式
NVIC_InitTypeDef NVIC_InitStructure; //结构体配置
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;//指定中断线
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;//响应中断优先级 0-14
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;//抢占中断优先级 0-14
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//开启
NVIC_Init(&NVIC_InitStructure);//初始化中断控制寄存器 引脚0
NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;//指定中断线
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;//响应中断优先级 0-14
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;//抢占中断优先级 0-14
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//开启
NVIC_Init(&NVIC_InitStructure);//初始化中断控制寄存器 引脚1
}
int16_t Encoder_Get(void)
{
int8_t temp;
temp = Encoder_Count;
Encoder_Count = 0;
return temp;
}
//10-15的中断处理函数 当发生中断就跳转到该函数 后要清楚中断标志位
void EXTI0_IRQHandler(void)
{ //检测是不是14引脚触发中断 SET触发中断
if(EXTI_GetITStatus(EXTI_Line0) == SET){//读取该引脚电平是否拉低 0 是count++
if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_0) == Bit_RESET){
Encoder_Count--;
}
EXTI_ClearITPendingBit(EXTI_Line0);
}
}
void EXTI1_IRQHandler(void)
{ //检测是不是14引脚触发中断 SET触发中断
if(EXTI_GetITStatus(EXTI_Line1) == SET){//读取该引脚电平是否拉低 0 是count++
if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1) == Bit_RESET){
Encoder_Count++;
}
EXTI_ClearITPendingBit(EXTI_Line1);
}
}
定时器
定时器类型
定时器时基----基本定时器
通用定时器时钟输入
高级定时器
代码部分-----------------------------
配置STM32F103C8T6标准库的定时器中断需要以下步骤:
- 使能时钟。
- 配置预分频、自动重装值和重复计数值。
- 清除中断标志位(否则会先进一次中断)。
- 使能TIM中断,选择中断源。
- 设置中断优先级。
- 使能TIMx外设。
#include "stm32f10x.h" // Device header
void Timer_Init()
{
//使能时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
TIM_InternalClockConfig(TIM2); //用于配置TIMx定时器的时钟源和分频值
//设置预分频自动重装值和重复计数 定时时间clk_psc/psc+1/次数 72000000/7200-1/10000-1 = 1秒
TIM_TimeBaseInitTypeDef TIM_TimBaseInitStructure;
TIM_TimBaseInitStructure.TIM_Prescaler = 7200 - 1; //设置定时器的预分频值
TIM_TimBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;//向上计数模式
TIM_TimBaseInitStructure.TIM_Period = 10000 - 1; //即定时器需要计数多少次才能溢出一次
TIM_TimBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;//置定时器的时钟分频系数为1,即不分频。
TIM_TimBaseInitStructure.TIM_RepetitionCounter = 0; //设置定时器的重复计数器值为0,用于启动定时器和计算定时器溢出时间。
TIM_TimeBaseInit(TIM2,&TIM_TimBaseInitStructure);
//清除中断标志位
TIM_ClearFlag(TIM2,TIM_FLAG_Update); //防止TIM_TimeBaseInit后就进入中断
//使能TIM中断
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
//设置中断优先级
NVIC_InitTypeDef NVIV_InitStructure;
NVIV_InitStructure.NVIC_IRQChannel = TIM2_IRQn;//中断通道
NVIV_InitStructure.NVIC_IRQChannelCmd = ENABLE;//启动中断
NVIV_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;//抢占优先级为2
NVIV_InitStructure.NVIC_IRQChannelSubPriority = 1; //响应优先级1
NVIC_Init(&NVIV_InitStructure);//中通道配置
//使能TIMx外设
TIM_Cmd(TIM2,ENABLE); //定时器2使能
}
/*
//定时器2中断
void TIM2_IRQHandler(void)
{
//判断是不是定时器2中断
if(TIM_GetITStatus(TIM2,TIM_IT_Update) == SET){
//清楚标志位
TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
}
}
*/
定时器电灯。
/*
定时器中断点灯
*/
#include "stm32f10x.h" // Device header
#include "LED.h"
void Timer_Init(void)
{
//设置时钟挂在APB1时钟上 为内部时钟72MHz
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
TIM_InternalClockConfig(TIM2);
//配置时基 72000000/7200/10000 = 1s
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;//几分频
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;//向上计数
TIM_TimeBaseInitStructure.TIM_Period = 10000-1;//周期
TIM_TimeBaseInitStructure.TIM_Prescaler = 7200-1;//psc获取定时器的预分频系数。这个参数决定了定时器的计数频率
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;//设置重复计数值 溢出增加计数 高级定时器才能用
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);
//设置运行控制 当指定的更新事件(通常是TIM_UpdateFlag)发生时,使能定时器的中断
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
//设置中断控制分组
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 = 2;//响应优先级
NVIC_Init(&NVIC_InitStructure);
//启动定时器
TIM_Cmd(TIM2,ENABLE);
}
void TIM2_IRQHandler(void)
{
if(TIM_GetITStatus(TIM2,TIM_IT_Update) == SET)
{
LED1_Turn();
TIM_ClearITPendingBit(TIM2,TIM_IT_Update);//用于清除定时器的某个中断挂起位的状态 以便重新激活
}
}
定时器 ---- PWM
概念
原理图
常用模式
CNT和CCR以及满刻度占比
计算公式
电路接线图
引脚复用 ---- 映射
计算公式
PWM控制呼吸灯 ----------------
/*
pwm.c pwm控制呼吸灯
*/
#include "stm32f10x.h" // Device header
void PWM_Init(void)
{
//1.1RCC时钟配置
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
TIM_InternalClockConfig(TIM2);
//2.1rcc 设置PPIOA时钟和复用口时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//GPIO0配置为复用推挽输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed= GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
//1.2定时器时基初始化
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;//不分频
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;//向上计数
TIM_TimeBaseInitStructure.TIM_Period = 100-1;//计数周期
TIM_TimeBaseInitStructure.TIM_Prescaler = 720-1;//psc预分频
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;//高级定时器才需要设置
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);
//3.1用于初始化定时器(TIM)的输出比较通道1(TIM_OC1)的功能
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCStructInit(&TIM_OCInitStructure);//!!用于初始化定时器的输出比较通道(Output Compare Channel)结构体 防止高级定时器参数过多冲突
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;//设置模式为PWM1
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;//高电平有效
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//PWM使能开启 TIM_OutputNState_Enable
TIM_OCInitStructure.TIM_Pulse = 0;//占空比百分之10
TIM_OC1Init(TIM2,&TIM_OCInitStructure);//定时器通道1PWM初始化
//1.3启动定时器
TIM_Cmd(TIM2,ENABLE);
}
//设置占空比 最后是1 不是L、l
void PWM_SetCompare1(uint16_t Comparel)
{
TIM_SetCompare1(TIM2,Comparel);//作用是设置 PWM 输出的占空比
}
/*
PWM.h
*/
#ifndef _PWM_H
#define _PWM_H
void PWM_Init(void);
void PWM_SetCompare1(uint16_t Comparel);
#endif
/*
main
*/
#include "stm32f10x.h" // Device header
#include "Shock.h"
#include "Buzzer.h"
#include "Delay.h"
#include "OLED.h"
#include "CountSensor.h"
#include "LED.h"
#include "Timer.h"
#include "PWM.h"
uint16_t i;
int main(void)
{
OLED_Init();
PWM_Init();
while (1)
{
for (i = 0; i <= 100; i++)
{
PWM_SetCompare1(i);
Delay_ms(10);
}
for (i = 0; i <= 100; i++)
{
PWM_SetCompare1(100 - i);
Delay_ms(10);
}
}
}
PWM控制SG90舵机----------------
使用定时器2通道2
/*
pwm.c pwm.h
*/
#include "stm32f10x.h" // Device header
void PWM_Init(void)
{
//1.1RCC时钟配置
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
TIM_InternalClockConfig(TIM2);
//1.2定时器时基初始化
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;//不分频
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;//向上计数
TIM_TimeBaseInitStructure.TIM_Period = 20000-1;//计数周期
TIM_TimeBaseInitStructure.TIM_Prescaler = 72-1;//psc预分频
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;//高级定时器才需要设置
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);
//2.1rcc 设置PPIOA时钟和复用口时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//GPIO0配置为复用推挽输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; //!!!第二通道对应PA1
GPIO_InitStructure.GPIO_Speed= GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
//3.1用于初始化定时器(TIM)的输出比较通道1(TIM_OC2)的功能
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCStructInit(&TIM_OCInitStructure);//!!用于初始化定时器的输出比较通道(Output Compare Channel)结构体
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;//设置模式为PWM1
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//PWM使能开启
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;//高电平有效
TIM_OCInitStructure.TIM_Pulse = 0;//占空比百分之10
TIM_OC2Init(TIM2,&TIM_OCInitStructure);//----用的定时器2通道 共用CNT寄存器 不同通道设置不同ARR
//1.3启动定时器
TIM_Cmd(TIM2,ENABLE);
}
//设置占空比 用的定时器通道2 接的SG90
void PWM_SetCompare2(uint16_t Compare)
{
TIM_SetCompare2(TIM2,Compare);//作用是设置 PWM 输出的占空比
}
#ifndef _PWM_H
#define _PWM_H
void PWM_Init(void);
void PWM_SetCompare2(uint16_t Compare);
#endif
SG90.c
/*
sg90.c
*/
#include "stm32f10x.h" // Device header
#include "PWM.h"
//SG90通过PWM初始化成0度
void SG90_Init(void)
{
PWM_Init();
PWM_SetCompare2(500);
}
//设置角度
void SG90_SetAngle(uint16_t angle)
{
PWM_SetCompare2(angle/180*2000 + 500);//2500占空比 180度2500/20000
}
/*
sg90.h
*/
#ifndef _SG90_H
#define _SG90_H
//SG90通过PWM初始化成0度
void SG90_Init(void);
//设置角度
void SG90_SetAngle(uint16_t angle);
#endif
PWM驱动电机模块
/*
pwm.c
*/
#include "stm32f10x.h" // Device header
void PWM_Init(void)
{
//1.1RCC时钟配置
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
TIM_InternalClockConfig(TIM2);
//1.2定时器时基初始化
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;//不分频
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;//向上计数
TIM_TimeBaseInitStructure.TIM_Period = 20000-1;//计数周期
TIM_TimeBaseInitStructure.TIM_Prescaler = 72-1;//psc预分频
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;//高级定时器才需要设置
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);
//2.1rcc 设置PPIOA时钟和复用口时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//GPIO0配置为复用推挽输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; //!!!定时器第三通道对应PA2
GPIO_InitStructure.GPIO_Speed= GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
//3.1用于初始化定时器(TIM)的输出比较通道1(TIM_OC2)的功能
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCStructInit(&TIM_OCInitStructure);//!!用于初始化定时器的输出比较通道(Output Compare Channel)结构体
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;//设置模式为PWM1
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//PWM使能开启
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;//高电平有效
TIM_OCInitStructure.TIM_Pulse = 0;//占空比百分之10
TIM_OC2Init(TIM2,&TIM_OCInitStructure);//----用的定时器2通道 共用CNT寄存器 不同通道设置不同ARR
//1.3启动定时器
TIM_Cmd(TIM2,ENABLE);
}
//设置占空比 用的定时器通道3 接的PA2 电机模块
void PWM_SetCompare3(int16_t Compare)
{
TIM_SetCompare3(TIM2,Compare);//作用是设置 PWM 输出的占空比
}
/*
Motor.c 电机模块 三根线 正反转PA4 PA5 pwm接PA2定时器2通道3
*/
#include "stm32f10x.h" // Device header
#include "PWM.h"
//电机初始化一个接PA4 一个接PA5 一个PWM接PA2
void Motor_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//上拉输入 看原理图
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4|GPIO_Pin_5;//接电机正负级
GPIO_InitStructure.GPIO_Speed= GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);//电机初始化
PWM_Init();
}
//设置电机速度、一高一低控制方向、pwm控制速度
void Motor_SetSpeed(int16_t Speed)
{
if(Speed >= 0){
GPIO_SetBits(GPIOA,GPIO_Pin_4);
GPIO_ResetBits(GPIOA,GPIO_Pin_5);
PWM_SetCompare3(Speed);
}else{
GPIO_ResetBits(GPIOA,GPIO_Pin_4);
GPIO_SetBits(GPIOA,GPIO_Pin_5);
PWM_SetCompare3(-Speed);
}
}
输入捕获测频率
/*
pwm
*/
#include "stm32f10x.h" // Device header
void PWM_Init(void)
{
//1.1RCC时钟配置
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
TIM_InternalClockConfig(TIM2);
//2.1rcc 设置PPIOA时钟和复用口时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//GPIO0配置为复用推挽输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed= GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
//1.2定时器时基初始化
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;//不分频
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;//向上计数
TIM_TimeBaseInitStructure.TIM_Period = 100-1;//计数周期
TIM_TimeBaseInitStructure.TIM_Prescaler = 720-1;//psc预分频
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;//高级定时器才需要设置
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);
//3.1用于初始化定时器(TIM)的输出比较通道1(TIM_OC1)的功能
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCStructInit(&TIM_OCInitStructure);//!!用于初始化定时器的输出比较通道(Output Compare Channel)结构体 防止高级定时器参数过多冲突
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;//设置模式为PWM1
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;//高电平有效
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//PWM使能开启 TIM_OutputNState_Enable
TIM_OCInitStructure.TIM_Pulse = 0;//占空比百分之10
TIM_OC1Init(TIM2,&TIM_OCInitStructure);//定时器通道1PWM初始化
//1.3启动定时器
TIM_Cmd(TIM2,ENABLE);
}
//设置占空比 最后是1 不是L、l
void PWM_SetCompare1(uint16_t Comparel)
{
TIM_SetCompare1(TIM2,Comparel);//作用是设置 PWM 输出的占空比
}
//设置PWM的预分频器Perscaler
//允许在运行时修改预分频器的值,而无需重新初始化整个定时器
//参数 TIM2 预分频 TIM_PSCReloadMode_Immediate立即重装载
void PWM_SetPrescaler(uint16_t Perscaler)
{
TIM_PrescalerConfig(TIM2,Perscaler,TIM_PSCReloadMode_Immediate);
}
/*
ic输入捕获
*/
#include "stm32f10x.h" // Device header
//输入捕获
//PA0发送占空比为50 预分频720的信号到PA6 PA6设置输入捕获获取PA0的频率并显示
void IC_Init(void)
{
//RCC
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
TIM_InternalClockConfig(TIM3);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
//时基
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;//不分频
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;//向上计数
TIM_TimeBaseInitStructure.TIM_Period = 65536 - 1;//计数周期
TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1;//psc预分频
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;//高级定时器才有
TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStructure);
//GPIO
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//上拉输入
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;//PA6
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//频率为50嘛MHz
GPIO_Init(GPIOA,&GPIO_InitStructure);
//输入捕获单元 用于初始化捕获通道、滤波器、捕获极性、映射关系和分频系数等参数
TIM_ICInitTypeDef TIM_ICInitStructure;
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;//通道
TIM_ICInitStructure.TIM_ICFilter = 0xF; //滤波器滤除干扰 越大越好
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;//极性 上升沿触发
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //不分频
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;//直连输入!! 交叉输入
TIM_ICInit(TIM3,&TIM_ICInitStructure);
//触发源 定时器3 通过TI1端(PA6)作为外部触发输入引脚的第1个边沿检测输入
TIM_SelectInputTrigger(TIM3,TIM_TS_TI1FP1);
//从模式用于选择定时器的从模式 复位从模式
TIM_SelectSlaveMode(TIM3,TIM_SlaveMode_Reset);
//开启定时器
TIM_Cmd(TIM3,ENABLE);
}
//获取频率
uint32_t IC_GetFreq(void)
{
//fx = fc/N
return 1000000 / (TIM_GetCapture1(TIM3) + 1);//N=10000 72MHz/720 TIM_GetCapture1获取定时器3捕获通道1的值
}
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "PWM.h"
#include "IC.h"
int main(void)
{
OLED_Init();
PWM_Init();
IC_Init();
OLED_ShowString(1,1,"Freq:00000Hz");
PWM_SetPrescaler(72 - 1);//设置预分频系数 Freq = 72MHz/psc+1/ARR+1 = 10000 PSC = 72000000/(psc+1)/100
PWM_SetCompare1(50);//设置占空比 Duty = CCR/100;
while (1)
{
OLED_ShowNum(1,6,IC_GetFreq(),5);
}
}
输入捕获测占空比
#include "stm32f10x.h" // Device header
void PWM_Init(void)
{
//1.1RCC时钟配置
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
TIM_InternalClockConfig(TIM2);
//2.1rcc 设置PPIOA时钟和复用口时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//GPIO0配置为复用推挽输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed= GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
//1.2定时器时基初始化
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;//不分频
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;//向上计数
TIM_TimeBaseInitStructure.TIM_Period = 100-1;//计数周期
TIM_TimeBaseInitStructure.TIM_Prescaler = 720-1;//psc预分频
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;//高级定时器才需要设置
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);
//3.1用于初始化定时器(TIM)的输出比较通道1(TIM_OC1)的功能
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCStructInit(&TIM_OCInitStructure);//!!用于初始化定时器的输出比较通道(Output Compare Channel)结构体 防止高级定时器参数过多冲突
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;//设置模式为PWM1
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;//高电平有效
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//PWM使能开启 TIM_OutputNState_Enable
TIM_OCInitStructure.TIM_Pulse = 0;//占空比百分之10
TIM_OC1Init(TIM2,&TIM_OCInitStructure);//定时器通道1PWM初始化
//1.3启动定时器
TIM_Cmd(TIM2,ENABLE);
}
//设置占空比 最后是1 不是L、l
void PWM_SetCompare1(uint16_t Comparel)
{
TIM_SetCompare1(TIM2,Comparel);//作用是设置 PWM 输出的占空比
}
//设置PWM的预分频器Perscaler
//允许在运行时修改预分频器的值,而无需重新初始化整个定时器
//参数 TIM2 预分频 TIM_PSCReloadMode_Immediate立即重装载
void PWM_SetPrescaler(uint16_t Perscaler)
{
TIM_PrescalerConfig(TIM2,Perscaler,TIM_PSCReloadMode_Immediate);
}
#include "stm32f10x.h" // Device header
//输入捕获
//PA0发送占空比为50 预分频720的信号到PA6 PA6设置输入捕获获取PA0的频率并显示
void IC_Init(void)
{
//RCC
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
TIM_InternalClockConfig(TIM3);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
//时基
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;//不分频
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;//向上计数
TIM_TimeBaseInitStructure.TIM_Period = 65536 - 1;//计数周期
TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1;//psc预分频
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;//高级定时器才有
TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStructure);
//GPIO
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//上拉输入
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;//PA6
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//频率为50嘛MHz
GPIO_Init(GPIOA,&GPIO_InitStructure);
//输入捕获单元 用于初始化捕获通道、滤波器、捕获极性、映射关系和分频系数等参数
TIM_ICInitTypeDef TIM_ICInitStructure;
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;//通道
TIM_ICInitStructure.TIM_ICFilter = 0xF; //滤波器滤除干扰 越大越好
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;//极性 上升沿触发
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //不分频
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;//直连输入!! 交叉输入
TIM_PWMIConfig(TIM3,&TIM_ICInitStructure);//~~~~!!!!!配置与前面的相反 通道2 下降沿 不分频 交叉输入
TIM_ICInit(TIM3,&TIM_ICInitStructure);
//触发源 定时器3 通过TI1端(PA6)作为外部触发输入引脚的第1个边沿检测输入
TIM_SelectInputTrigger(TIM3,TIM_TS_TI1FP1);
//从模式用于选择定时器的从模式 复位从模式
TIM_SelectSlaveMode(TIM3,TIM_SlaveMode_Reset);
//开启定时器
TIM_Cmd(TIM3,ENABLE);
}
//获取频率 两个一样的标准72频率 占周期N的分之一
uint32_t IC_GetFreq(void)
{
//fx = fc/N 一格/N格 即周期分之一 就是频率
return 1000000 / (TIM_GetCapture1(TIM3) + 1);//N=100000 72MHz/720 TIM_GetCapture1获取定时器3捕获通道1的值
} //TIM_GetCapture1捕获的是计数器的值。当定时器溢出时,计数器的值会被自动重置为0
//获取占空比
uint32_t IC_GetDuty(void)
{
//获取通道2的N的次数单次 总的次数放在通道1中计数
return (TIM_GetCapture2(TIM3) * 100) / (TIM_GetCapture1(TIM3) + 1);
}
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "PWM.h"
#include "IC.h"
int main(void)
{
OLED_Init();
PWM_Init();
IC_Init();
OLED_ShowString(1,1,"Freq:00000Hz");
OLED_ShowString(2,1,"Duty:00%");
PWM_SetPrescaler(7200 - 1);//设置预分频系数 Freq = 72MHz/psc+1/ARR+1 = 10000 PSC = 72000000/(psc+1)/100
PWM_SetCompare1(80);//设置占空比 Duty = CCR/100;
while (1)
{
OLED_ShowNum(1,6,IC_GetFreq(),5);
OLED_ShowNum(2,6,IC_GetDuty(),2);
}
}
输入捕获编码器计数
TIM_EncoderInterfaceConfig 是一个用于配置定时器编码器接口参数的函数。这个函数通常在STM32微控制器编程中使用,用于设置定时器的编码器模式、分辨率等参数。
函数原型:
c复制代码
void TIM_EncoderInterfaceConfig(TIM_TypeDef* TIMx, uint16_t EncoderMode, uint16_t IC1Filter, uint16_t IC1Polarity, uint16_t IC1Selection, uint16_t IC2Filter, uint16_t IC2Polarity, uint16_t IC2Selection);
参数:
- TIMx:定时器模块的实例,可以是 TIM2、TIM3、TIM4、TIM5 等。
- EncoderMode:编码器模式,可以是 TIM_EncoderMode_TI12、TIM_EncoderMode_TI1、TIM_EncoderMode_TI2 或 TIM_EncoderMode_TI4。
- IC1Filter:输入滤波器1的值,用于设置输入信号的滤波程度。
- IC1Polarity:输入极性1的值,用于设置输入信号的极性。
- IC1Selection:输入选择1的值,用于选择输入通道。
- IC2Filter:输入滤波器2的值,用于设置输入信号的滤波程度。
- IC2Polarity:输入极性2的值,用于设置输入信号的极性。
- IC2Selection:输入选择2的值,用于选择输入通道。
#include "stm32f10x.h" // Device header
//编码器配置
void Encoder_Init(void)
{
//RCC时钟配置
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
TIM_InternalClockConfig(TIM3);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
//时基 使用定时器3 因为定时器2到普通时钟了
TIM_TimeBaseInitTypeDef TIM_TimeBaseIniitStructure;
TIM_TimeBaseIniitStructure.TIM_ClockDivision = TIM_CKD_DIV1;//预分频因子 不分频
TIM_TimeBaseIniitStructure.TIM_CounterMode = TIM_CounterMode_Up;//定时器模式为向上计数
TIM_TimeBaseIniitStructure.TIM_Period = 65536-1;//计数周期为16为寄存器挤满65536
TIM_TimeBaseIniitStructure.TIM_Prescaler = 1-1;//不分频
TIM_TimeBaseIniitStructure.TIM_RepetitionCounter = 0;//高级定时器才有
TIM_TimeBaseInit(TIM3,&TIM_TimeBaseIniitStructure);
//GPIO初始化配置
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//引脚模式为上拉输入
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
//PWM输入捕获配置
TIM_ICInitTypeDef TIM_ICInitStructure;
TIM_ICStructInit(&TIM_ICInitStructure);//参数过多没有配置 放入结构体中防止冲突
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;//输入捕获 定时器通道1
TIM_ICInitStructure.TIM_ICFilter = 0xF;//滤波器越大越好
TIM_ICInit(TIM3,&TIM_ICInitStructure);//配置完输入捕获通道1 写入寄存器中
TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;//输入捕获 定时器通道2
TIM_ICInitStructure.TIM_ICFilter = 0xF;//滤波器越大越好
TIM_ICInit(TIM3,&TIM_ICInitStructure);//配置完输入捕获通道2 写入寄存器中
//Encoder配置 里面极性TIM_ICPolarity_Rising 会覆盖输入捕获中的极性 必须在后面 前面极性可省略
TIM_EncoderInterfaceConfig(TIM3,TIM_EncoderMode_TI12,TIM_ICPolarity_Rising,TIM_ICPolarity_Rising);
//开启时钟
TIM_Cmd(TIM3,ENABLE);
}
//获取count值
int16_t Encoder_Get(void)
{
int16_t Temp;
Temp = TIM_GetCounter(TIM3);//用于获取定时器计数器的函数
TIM_SetCounter(TIM3,0); //用于设置定时器计数器的函数
return Temp;
}
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "PWM.h"
#include "Timer.h"
#include "Encoder.h"
int16_t Speed;
int main(void)
{
OLED_Init();
PWM_Init();
Encoder_Init();
Timer_Init();
OLED_ShowString(1,1,"Speed:");
while (1)
{
OLED_ShowSignedNum(1,7,Speed,5);
}
}
void TIM2_IRQHandler(void)//每秒钟获取以下speed速度
{
if(TIM_GetITStatus(TIM2,TIM_IT_Update) == SET)
{
Speed = Encoder_Get();
TIM_ClearITPendingBit(TIM2,TIM_IT_Update);//用于清除定时器的某个中断挂起位的状态 以便重新激活
}
}
/*
定时器
*/
#include "stm32f10x.h" // Device header
#include "LED.h"
void Timer_Init(void)
{
//设置时钟挂在APB1时钟上 为内部时钟72MHz
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
TIM_InternalClockConfig(TIM2);
//配置时基 72000000/7200/10000 = 1s
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;//几分频
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;//向上计数
TIM_TimeBaseInitStructure.TIM_Period = 10000-1;//周期
TIM_TimeBaseInitStructure.TIM_Prescaler = 7200-1;//psc获取定时器的预分频系数。这个参数决定了定时器的计数频率
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;//设置重复计数值 溢出增加计数 高级定时器才能用
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);
//设置运行控制 当指定的更新事件(通常是TIM_UpdateFlag)发生时,使能定时器的中断
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
//设置中断控制分组
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 = 2;//响应优先级
NVIC_Init(&NVIC_InitStructure);
//启动定时器
TIM_Cmd(TIM2,ENABLE);
}
//void TIM2_IRQHandler(void) 是否在主函数中调用了
//{
// if(TIM_GetITStatus(TIM2,TIM_IT_Update) == SET)
// {
// LED1_Turn();
// TIM_ClearITPendingBit(TIM2,TIM_IT_Update);//用于清除定时器的某个中断挂起位的状态 以便重新激活
// }
//}