STM32 ---- 再次学习STM32F103C8T6/STM32F409IGT6

news2024/11/30 6:49:27

目录

一、环境搭建及介绍

关于STM32基础介绍

 新建工程

外设案例

LED流水灯

蜂鸣器

 上拉电阻和下拉电阻知识

电压比较器

 c语言基础知识 类型、结构体、枚举

类型int8_t int16_t int32_t

 宏替换 #define 和typedef用法   

结构体两种填充方法 和 命名规则

枚举用法

常用配置

输入输出模式

GPIO常用库函数

 中断函数

模块化编程 

延时函数  System

 LED函数  Hardwore

  按键函数  Hardwore

   蜂鸣器函数  Hardwore

 震动模块 Hardwore

 OLED IIC模块Hardwore

调试方法

 中断系统

概念:

NVIC中断控制寄存器结构 

 NVIC分组 抢占优先级和响应优先级​编辑

中断配置 --代码-----------------

两个中断时

定时器

定时器类型

定时器时基----基本定时器

通用定时器时钟输入

​编辑 高级定时器​编辑

代码部分-----------------------------

定时器 ---- PWM

PWM控制呼吸灯 ----------------

PWM控制SG90舵机----------------

PWM驱动电机模块

输入捕获测频率

输入捕获测占空比

输入捕获编码器计数


一、环境搭建及介绍

kile4 开发51单片机(内置芯片包)、kile_v5开发STM32手动添加芯片包、如果要开发51许把51的芯片包放在kile5中 、通过注册机key来破解

对应STM芯片包

也可以通过 通过在线安装其它芯片包 ---- 可以找到GD 以及其他厂家的芯片包

STLink驱动 和CH340驱动安装

 管理员运行kile5 复制CLD到注册机 破解

关于STM32基础介绍

片上资源

 系统结构

 

启动过程

新建工程

 GPIO介绍

 

 GPIO八种模式

输入配置
I/O 端口配置为输入时:
● 输出缓冲器被禁止
● 施密特触发输入被激活
● 根据输入配置 ( 上拉,下拉或浮动 ) 的不同,弱上拉和下拉电阻被连接
● 出现在 I/O 脚上的数据在每个 APB2 时钟被采样到输入数据寄存器
● 对输入数据寄存器的读访问可得到 I/O 状态

 

输出配置
I/O 端口被配置为输出时
● 输出缓冲器被激活
开漏模式:输出寄存器上的 0 激活 N-MOS ,而输出寄存器上的 1 将端口置于高阻状态 (P
MOS 从不被激活 )
推挽模式:输出寄存器上的 0 激活 N-MOS ,而输出寄存器上的 1 将激活 P-MOS
● 施密特触发输入被激活
● 弱上拉和下拉电阻被禁止
● 出现在 I/O 脚上的数据在每个 APB2 时钟被采样到输入数据寄存器
● 在开漏模式时,对输入数据寄存器的读访问可得到 I/O 状态
● 在推挽式模式时,对输出数据寄存器的读访问得到最后一次写的值。

 

复用功能配置
I/O 端口被配置为复用功能时:
● 在开漏或推挽式配置中,输出缓冲器被打开
● 内置外设的信号驱动输出缓冲器 ( 复用功能输出 )
● 施密特触发输入被激活
● 弱上拉和下拉电阻被禁止
● 在每个 APB2 时钟周期,出现在 I/O 脚上的数据被采样到输入数据寄存器
● 开漏模式时,读输入数据寄存器时可得到 I/O 口状态
● 在推挽模式时,读输出数据寄存器时可得到最后一次写的值

模拟输入配置
I/O 端口被配置为模拟输入配置时:
● 输出缓冲器被禁止;
● 禁止施密特触发输入,实现了每个模拟 I/O 引脚上的零消耗。施密特触发输出值被强置
’0’
● 弱上拉和下拉电阻被禁止;
● 读取输入数据寄存器时数值为 ’0’

 

 新建工程

 

 

 电灯流程 配置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常用库函数

  1. void GPIO_DeInit(GPIO_TypeDef* GPIOx):用于将指定GPIO端口的所有配置重置为默认值。

  2. void GPIO_AFIODeInit(void):用于将AFIO(Alternate Function I/O)寄存器的配置重置为默认值。

  3. void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct):用于初始化指定GPIO端口的引脚配置。通过GPIO_InitStruct结构体参数传递引脚相关配置,如引脚编号、引脚模式、引脚速度、引脚上拉/下拉等。

  4. void GPIO_StructInit(GPIO_InitTypeDef* GPIO_InitStruct):用于将GPIO_InitStruct结构体中的成员设置为默认值。
     


  5. uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin):用于读取指定GPIO端口指定引脚号的输入电平(逻辑高或逻辑低)。

  6. uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx):用于读取指定GPIO端口的全部输入引脚的电平状态。

  7. uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin):用于读取指定GPIO端口指定引脚号的输出电平(逻辑高或逻辑低)。

  8. uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx):用于读取指定GPIO端口的全部输出引脚的电平状态。
     


  9. void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin):用于将指定GPIO端口中指定引脚置为逻辑高电平。

  10. void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin):用于将指定GPIO端口中指定引脚置为逻辑低电平。

  11. void GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal):用于设置指定GPIO端口中指定引脚的输出电平,BitVal参数可设置为Bit_RESET(低电平)或Bit_SET(高电平)。

  12. void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal):用于设置指定GPIO端口的全部输出引脚的电平状态。PortVal参数是一个16位的数值,每个位对应一个引脚,可设置为逻辑低或逻辑高。
     


  13. void GPIO_PinLockConfig(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin):用于锁定指定GPIO端口的指定引脚,防止意外改变其配置。

  14. void GPIO_EventOutputConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource):用于配置GPIO的事件输出功能,将指定的GPIO端口和引脚映射到事件输出信号线上。

  15. void GPIO_EventOutputCmd(FunctionalState NewState):用于使能或禁用GPIO的事件输出功能。

  16. void GPIO_PinRemapConfig(uint32_t GPIO_Remap, FunctionalState NewState):用于重新映射GPIO端口的引脚,将其连接到其他IO端口或功能。

  17. void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource):用于配置GPIO的外部中断线路,将指定的GPIO端口和引脚映射到外部中断线上。

  18. void GPIO_ETH_MediaInterfaceConfig(uint32_t GPIO_ETH_MediaInterface):用于配置GPIO端口的以太网媒体接口(MII或RMII)。

 中断函数

  1. void EXTI_DeInit(void):用于将外部中断配置重置为默认值。

  2. void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct):用于根据指定的配置参数初始化外部中断。

  3. void EXTI_StructInit(EXTI_InitTypeDef* EXTI_InitStruct):用于将外部中断配置结构体EXTI_InitStruct的成员设置为默认值。

  4. void EXTI_GenerateSWInterrupt(uint32_t EXTI_Line):用于生成指定外部中断线的软件中断。可以用于模拟外部中断触发。

  5. FlagStatus EXTI_GetFlagStatus(uint32_t EXTI_Line):用于获取指定外部中断线的中断标志状态。返回值为SET(中断标志置位)或RESET(中断标志未置位)。

  6. void EXTI_ClearFlag(uint32_t EXTI_Line):用于清除指定外部中断线的中断标志。将中断标志置位。

  7. ITStatus EXTI_GetITStatus(uint32_t EXTI_Line):用于获取指定外部中断线的中断状态。返回值为SET(中断状态已触发)或RESET(中断状态未触发)。

  8. 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标准库的定时器中断需要以下步骤:

  1. 使能时钟。
  2. 配置预分频、自动重装值和重复计数值。
  3. 清除中断标志位(否则会先进一次中断)。
  4. 使能TIM中断,选择中断源。
  5. 设置中断优先级。
  6. 使能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);//用于清除定时器的某个中断挂起位的状态 以便重新激活
//	}
//}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1095841.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

云安全——云计算基础

0x00 前言 学习云安全&#xff0c;那么必然要对云计算相关的内容进行学习和了解&#xff0c;所以云安全会分为两个部分来进行&#xff0c;首先是云计算先关的内容。 0x01 云计算 广泛传播 云计算最早大范围传播是2006年&#xff0c;8月&#xff0c;在圣何塞【1】举办的SES&a…

Vs2017搭建QT开发环境

前置条件&#xff1a; vs2017 前提需要安装Qt的插件 &#xff1a; 若是没有&#xff0c;通过 “工具->扩展和更新->联机->Qt Visual Studio Tools”&#xff0c;安装Qt Visual Studio Tools 1、新建工程"文件->新建->项目"&#xff0c;出现如下界面…

Yakit工具篇:爆破与未授权检测的使用

简介(来自官方文档) 爆破和未授权检测是网络安全领域中一种常见的测试技术&#xff0c;其主要目的是测试系统或应用程序中的口令是否强健&#xff0c;Yakit的爆破与未授权检测模块则实现了该部分的内容。 这个模块可以对多种常见协议和服务&#xff08;如ftp、memcached、mon…

【操作系统】信号量机制(整型信号量、记录型信号量),用信号量实现进程互斥、同步、前驱关系

&#x1f40c;个人主页&#xff1a; &#x1f40c; 叶落闲庭 &#x1f4a8;我的专栏&#xff1a;&#x1f4a8; c语言 数据结构 javaEE 操作系统 Redis 石可破也&#xff0c;而不可夺坚&#xff1b;丹可磨也&#xff0c;而不可夺赤。 信号量 一、信号量机制1.1 整型信号量1.2 记…

05_51单片机led流水线的实现

1:step创建一个新的项目并将程序烧录进入51单片机 以下是51单片机流水线代码的具体实现 #include <REGX52.H>void Delay500ms() //11.0592MHz {unsigned char i, j, k;i 4;j 129;k 119;do{do{while (--k);} while (--j);} while (--i); }void main(){while(1){P1 0…

深入理解React中的useEffect钩子函数

引言&#xff1a; React是一种流行的JavaScript库&#xff0c;它通过组件化和声明式编程的方式简化了前端开发。在React中&#xff0c;一个核心概念是组件的生命周期&#xff0c;其中包含了许多钩子函数&#xff0c;用于管理组件的不同阶段。其中之一就是useEffect钩子函数&…

完成了一个小项目:修改了一个用PHP+MySQL写的建网站用的CMS原程序

最近一段时间&#xff0c;我建了一个网站。建一个网站及简单也复杂。要功能合适&#xff0c;界面合适&#xff0c;也不是容易的事。开始用了一个现成的建站软件WordPress&#xff0c;但是对界面不满意。后来找了另外一个带源码的程序&#xff0c;修改该程序花了十多天时间。到目…

metaRTC7集成lvgl ui demo编译指南

概要 开源轻量级嵌入式图形库lvgl:Light and Versatile Graphics Library&#xff0c;最低只需8kb内存&#xff0c;可为任何 MCU、MPU 和显示类型创建漂亮的 UI。 metaRTC新增lvgl demo&#xff0c;可在linux下编译运行。 源码下载 https://github.com/metartc/metaRTC/rel…

Spring Cloud的革新:服务网格和云原生整合

文章目录 介绍Spring Cloud服务网格的兴起Spring Cloud与Service Mesh的整合1. 服务发现2. 负载均衡3. 故障处理4. 安全性 云原生整合结论 &#x1f389;欢迎来到架构设计专栏~Spring Cloud的革新&#xff1a;服务网格和云原生整合 ☆* o(≧▽≦)o *☆嗨~我是IT陈寒&#x1f37…

【力扣1876】长度为三且各字符不同的子字符串

&#x1f451;专栏内容&#xff1a;力扣刷题⛪个人主页&#xff1a;子夜的星的主页&#x1f495;座右铭&#xff1a;前路未远&#xff0c;步履不停 目录 一、题目描述二、题目分析 一、题目描述 题目链接&#xff1a;长度为三且各字符不同的子字符串 如果一个字符串不含有任何…

一卷到底,大明哥带你横扫 Netty

上一个死磕 Java 专栏【死磕 NIO】(当然写的不是很好&#xff0c;争取今年将它重写一遍)是**【死磕 Netty】**的铺垫&#xff0c;对于我们 Java 程序员而言&#xff0c;我们在实际开发过程一般都不会直接使用 Java NIO 作为我们的网络编程框架&#xff0c;因为写出一套高质量的…

【C++初阶(二)缺省参数与函数重载】

本专栏内容为&#xff1a;C学习专栏&#xff0c;分为初阶和进阶两部分。 通过本专栏的深入学习&#xff0c;你可以了解并掌握C。 &#x1f493;博主csdn个人主页&#xff1a;小小unicorn ⏩专栏分类&#xff1a;C &#x1f69a;代码仓库&#xff1a;小小unicorn的代码仓库&…

Kwik Trip IT系统遭遇神秘的“网络事件”导致系统故障

导语 近日&#xff0c;美国连锁便利店和加油站Kwik Trip遭遇了一系列神秘的业务中断&#xff0c;这很可能是一次赎金软件攻击。本文将为您详细介绍此次事件的背景和影响&#xff0c;并探讨赎金软件攻击对企业和个人的危害。 神秘的“网络事件” Kwik Trip是一家在密歇根州、明尼…

云上攻防-云原生篇K8s安全Config泄漏Etcd存储Dashboard鉴权Proxy暴露

文章目录 云原生-K8s安全-etcd未授权访问云原生-K8s安全-Dashboard未授权访问云原生-K8s安全-Configfile鉴权文件泄漏云原生-K8s安全-Kubectl Proxy不安全配置 云原生-K8s安全-etcd未授权访问 攻击2379端口&#xff1a;默认通过证书认证&#xff0c;主要存放节点的数据&#x…

14 | 乐观锁机制和重试机制在实战中应该怎么用

什么是乐观锁&#xff1f; 乐观锁在实际开发过程中很常用&#xff0c;它没有加锁、没有阻塞&#xff0c;在多线程环境以及高并发的情况下 CPU 的利用率是最高的&#xff0c;吞吐量也是最大的。 而 Java Persistence API 协议也对乐观锁的操作做了规定&#xff1a;通过指定 Ve…

服务器感染了.360、.halo勒索病毒,如何确保数据文件完整恢复?

导言&#xff1a; 数据的安全性至关重要&#xff0c;但威胁不断进化&#xff0c;.360、.halo勒索病毒是其中的令人担忧的勒索软件。本文91数据恢复将深入介绍.360、.halo勒索病毒&#xff0c;包括其威胁本质、数据恢复方法和如何采取预防措施来保护您的数据。 如果受感染的数据…

智慧公厕高精尖技术揭秘,让卫生管理更智能、更舒适

随着科技的飞速发展&#xff0c;智慧公厕正逐渐走进人们的生活。借助物联网、互联网、云计算、大数据、人工智能、自动化控制等技术的应用&#xff0c;智慧公厕将卫生管理提升到一个全新的水平&#xff0c;为公众打造了清洁舒适的使用环境。本文以智慧公厕源头厂家广州中期科技…

94. 二叉树的中序遍历(递归+迭代)

题目链接&#xff1a;力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 解题思路&#xff1a; 方法一&#xff1a;递归 中序遍历的操作定义为&#xff0c;若二叉树为空&#xff0c;则空操作&#xff0c;否则&#xff1a; 中序遍历左子树访问根节点中…

✔ ★【备战实习(面经+项目+算法)】 10.15学习时间表

✔ ★【备战实习&#xff08;面经项目算法&#xff09;】 坚持完成每天必做如何找到好工作1. 科学的学习方法&#xff08;专注&#xff01;效率&#xff01;记忆&#xff01;心流&#xff01;&#xff09;2. 每天认真完成必做项&#xff0c;踏实学习技术 认真完成每天必做&…

【Vue面试题二十六】、SSR解决了什么问题?有做过SSR吗?你是怎么做的?

文章底部有个人公众号&#xff1a;热爱技术的小郑。主要分享开发知识、学习资料、毕业设计指导等。有兴趣的可以关注一下。为何分享&#xff1f; 踩过的坑没必要让别人在再踩&#xff0c;自己复盘也能加深记忆。利己利人、所谓双赢。 面试官&#xff1a;SSR解决了什么问题&…