一、前言
由于各位对于的单片机较为生疏,在此我再仔细介绍一下单片机。
俗话说,以项目驱动学习,才是学习快速的秘诀
通过一次次的项目才能更加对某一个东西熟悉。
废话不多说,直接开始做
如果对单片机不熟悉的话,可以看我的另一篇blog(虽然还没更完)
二、所需模块
一个stm32模块,任何型号都可以,因为这个项目所需的资源不是太多,当然了,太老太旧的型号也是不行的。
下图是stm32f103c8t6
有单片机也要有电源是吧,这里使用了一个12V的电源,因为它比较方便
有电源也要有处理电源的东西,一般我们使用AMS1117芯片去降压,也用LDO电路和DC-DC电路去升降压,不过有现成的模块会方便一点。以上仅限于直流电,交流电需要变压器,很大的那种或者其他奇奇怪怪的电路。
这里使用了一个7针的OLED,它可以使用I2C和SPI通信协议进行通信。比较方便、便宜。主要是用来显示灯的挡位的,没有的话也可以,通过观察LED的亮度就可以。
一个直插式小LED,电压大概是3V左右,电流18mA跟单片机的电流差很多,不过不并联电阻也是可以的,就算炸了也没事,一块钱一大堆,炸了也是给自己的教训。一般的LED不会爆炸,只会融化损毁,除非你的LED与众不同。
准备好上面这些东西就可以做了。
是不是还不错,虽然有点丑,不过没关系,能用就行,主要这是我拆了我的小风扇做的。
三、代码
代码一,主函数代码
static u8 title2[5][32] = {
{0x08,0x00,0x29,0x00,0xCA,0x00,0x4C,0xFF,0x78,0x92,0x4C,0x92,0x4A,0x92,0x08,0x92,0x00,0x92,0x7E,0x92,0x42,0x92,0x42,0xFF,0x42,0x00,0x7E,0x00,0x00,0x00,0x00,0x00},/*"智",4*/
{0x10,0x00,0x33,0xFF,0x52,0x48,0x92,0x48,0x12,0x4A,0x52,0x49,0x33,0xFE,0x18,0x00,0x00,0x00,0xFE,0x7E,0x11,0x11,0x11,0x11,0x21,0x21,0x41,0x41,0x07,0x07,0x00,0x00},/*"能",5*/
{0x00,0x10,0x00,0x20,0x00,0xC0,0x07,0x00,0x00,0x00,0x00,0x02,0x00,0x01,0xFF,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x02,0x00,0x01,0x80,0x00,0x70,0x00,0x00},/*"小",6*/
{0x00,0x00,0x02,0x00,0x07,0x00,0x0A,0x7F,0x12,0x42,0x22,0x42,0xC2,0x42,0x02,0x42,0x02,0x42,0x02,0x42,0x12,0x42,0x0A,0x7F,0x06,0x00,0x03,0x00,0x00,0x00,0x00,0x00},/*"台",7*/
{0x01,0x01,0x0E,0x06,0x00,0x18,0xFF,0xE0,0x04,0x10,0x08,0x0C,0x20,0x00,0x20,0x00,0x20,0x02,0x20,0x01,0x3F,0xFE,0x20,0x00,0x20,0x00,0x20,0x00,0x20,0x00,0x00,0x00},/*"灯",8*/
};
int main(void)
{
InitSoftware(); //初始化软件相关函数
InitHardware(); //初始化硬件相关函数
printf("Init System has been finished.\r\n" ); //打印系统状态
OLEDShowChinese(4,16,Hzk,2,16,0);
OLEDShowChinese(28,0,title2,5,16,1);
while(1)
{
CalcPWM();
}
}
是不是非常简单?除了一个OLED的取模。
CalcPWM是用来控制PWM的,以此来控制LED的亮度。这里我使用了一个函数来进行实现。
OLED取模是需要配合自己的OLED代码的,我这里使用了顺向逐列式,当然了,也可以使用其他取模方法。自定义格式一定要使用c51除非有特殊说明。最好是使用十六进制,因为十六进制更加符合OLED屏幕的排列方式。
更多的OLED知识需要自行寻找。
一般我们使用PCtoLCD去取模,不过也可以使用其他软件,在百度上搜一个也可以。(我会上传)
代码二、按键
因为我使用的是矩阵按键,且较为便宜,因此,不太好用,不过使用开发板的话是可以避免的,可以加一个上拉或下拉电阻,再加一个电容滤波,最后得到的按键信号是较为稳定的。
这里使用44的矩阵按键,就是4行4列等于16按键,是不是十分巧妙。因此只需要8根线就可以控制16个按键了。
代码如下:
#include "stm32f10x.h"
#include "stm32f10x_rcc.h"
#include "SysTick.h"
#include "LED.h"
#include "KEY.h"
int key_val = -1;
void InitKeyBoard(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU ;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
GPIO_Init(GPIOB,&GPIO_InitStructure);
}
*/
u16 keyboard_scan(void)
{
u8 temp = 0;
GPIO_ResetBits(GPIOB,GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10|GPIO_Pin_11); //拉低行线
DelayNms(10);
temp=(GPIO_ReadInputData(GPIOB) >> 8)&0xff;
//没有按键按下时扫描
if (temp == 0xf0)
{
DelayNms(50);
GPIO_ResetBits(GPIOB,GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10|GPIO_Pin_11); //拉低行线
DelayNus(10);
temp=(GPIO_ReadInputData(GPIOB) >> 8)&0xff;
if (temp != 0xf0) //按键按下时,对键值进行赋值
{
//第一行
GPIO_Write(GPIOB,0);
DelayNms(5);
GPIO_Write(GPIOB,(uint16_t)(0xFE << 8));
if(((GPIO_ReadInputData(GPIOB) >> 8) & 0XF0) != 0XF0)
{
DelayNms(20);//消抖
if(((GPIO_ReadInputData(GPIOB) >> 8) & 0XF0) != 0XF0)
{
temp=((GPIO_ReadInputData(GPIOB) >> 8) & 0XFE); //对列进行扫描
switch(temp)
{
case 0xEE: key_val = 1; break;
case 0xDE: key_val = 2; break;
case 0xBE: key_val = 3; break;
case 0x7E: key_val = 4; break;
default: key_val = -1; break;
}
}
}
//第二行
GPIO_Write(GPIOB,0);
DelayNms(5);
GPIO_Write(GPIOB,(uint16_t)(0xFD << 8));
if(((GPIO_ReadInputData(GPIOB) >> 8) & 0XF0)!= 0XF0)
{
DelayNms(20);
if(((GPIO_ReadInputData(GPIOB) >> 8) & 0XF0) != 0XF0)
{
temp=((GPIO_ReadInputData(GPIOB) >> 8) & 0XFD);
switch(temp)
{
case 0xED: key_val = 5; break;
case 0xDD: key_val = 6; break;
case 0xBD: key_val = 7; break;
case 0x7D: key_val = 8; break;
default: key_val = -1; break;
}
}
}
//第三行
GPIO_Write(GPIOB,0);
DelayNms(5);
GPIO_Write(GPIOB,(uint16_t)(0xFB << 8));
if(((GPIO_ReadInputData(GPIOB) >> 8) & 0XF0) != 0XF0)
{
DelayNms(20);
if(((GPIO_ReadInputData(GPIOB) >> 8) & 0XF0) != 0XF0)
{
temp=((GPIO_ReadInputData(GPIOB) >> 8) & 0XFB);
switch(temp)
{
case 0xEB: key_val = 9; break;
case 0xDB: key_val = 10; break;
case 0xBB: key_val = 11; break;
case 0x7B: key_val = 12; break;
default: key_val = -1; break;
}
}
}
//第四行
GPIO_Write(GPIOB,0);
DelayNms(5);
GPIO_Write(GPIOB,(uint16_t)(0xF7 << 8));
if(((GPIO_ReadInputData(GPIOB) >> 8) & 0XF0) !=0XF0)
{
DelayNms(20);
if(((GPIO_ReadInputData(GPIOB) >> 8) & 0XF0) != 0XF0)
{
temp=((GPIO_ReadInputData(GPIOB) >> 8) & 0XF7);
switch(temp)
{
case 0xE7: key_val = 13; break;
case 0xD7: key_val = 14; break;
case 0xB7: key_val = 15; break;
case 0x77: key_val = 16; break;
default: key_val = -1; break;
}
}
}
}
}
return key_val;
}
这个代码可以自己琢磨一下,还是非常巧妙的。
代码三
/*********************************************************************************************************
* 模块名称:OLED.c
* 摘 要:OLED显示屏模块,4线串行接口,CS、DC、SCK、DIN、RES
* 当前版本:1.0.0
* 作 者:SZLY(COPYRIGHT 2018 - 2020 SZLY. All rights reserved.)
* 完成日期:2020年01月01日
* 内 容:
* 注 意:OLED的显存
存放格式如下.
[0]0 1 2 3 ... 127
[1]0 1 2 3 ... 127
[2]0 1 2 3 ... 127
[3]0 1 2 3 ... 127
[4]0 1 2 3 ... 127
[5]0 1 2 3 ... 127
[6]0 1 2 3 ... 127
[7]0 1 2 3 ... 127
**********************************************************************************************************
* 取代版本:
* 作 者:
* 完成日期:
* 修改内容:
* 修改文件:
*********************************************************************************************************/
/*********************************************************************************************************
* 包含头文件
*********************************************************************************************************/
#include "OLED.h"
#include "stm32f10x_conf.h"
#include "OLEDFont.h"
#include "SysTick.h"
#include "DelayNms.h"
/*********************************************************************************************************
* 宏定义
*********************************************************************************************************/
#define OLED_CMD 0 //命令
#define OLED_DATA 1 //数据
//OLED端口定义
#define CLR_OLED_CS() GPIO_ResetBits(GPIOA, GPIO_Pin_4) //CS,片选
#define SET_OLED_CS() GPIO_SetBits (GPIOA, GPIO_Pin_4)
#define CLR_OLED_RES() GPIO_ResetBits(GPIOA, GPIO_Pin_6) //RES,复位
#define SET_OLED_RES() GPIO_SetBits (GPIOA, GPIO_Pin_6)
#define CLR_OLED_DC() GPIO_ResetBits(GPIOB, GPIO_Pin_11) //DC,命令数据标志(0-命令/1-数据)
#define SET_OLED_DC() GPIO_SetBits (GPIOB, GPIO_Pin_11)
#define CLR_OLED_SCK() GPIO_ResetBits(GPIOA, GPIO_Pin_5) //SCK,时钟
#define SET_OLED_SCK() GPIO_SetBits (GPIOA, GPIO_Pin_5)
#define CLR_OLED_DIN() GPIO_ResetBits(GPIOA, GPIO_Pin_7) //DIN,数据
#define SET_OLED_DIN() GPIO_SetBits (GPIOA, GPIO_Pin_7)
/*********************************************************************************************************
* 枚举结构体定义
*********************************************************************************************************/
/*********************************************************************************************************
* 内部变量
*********************************************************************************************************/
static u8 s_arrOLEDGRAM[132][8]; //OLED显存缓冲区
/*********************************************************************************************************
* 内部函数声明
*********************************************************************************************************/
static void ConfigOLEDGPIO(void); //配置OLED的GPIO
static void ConfigOLEDReg(void); //配置OLED的SSD1306寄存器
static u32 CalcPow(u8 m, u8 n); //计算m的n次方
/*********************************************************************************************************
* 内部函数实现
*********************************************************************************************************/
/*********************************************************************************************************
* 函数名称:ConfigOLEDGPIO
* 函数功能:配置OLED的GPIO
* 输入参数:void
* 输出参数:void
* 返 回 值:void
* 创建日期:2018年01月01日
* 注 意:PB12(OLED_CS)、PB14(OLED_RES)、PB11(OLED_DC)、PB13(OLED_SCK)、PB15(OLED_DIN)
*********************************************************************************************************/
static void ConfigOLEDGPIO(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
//使能RCC相关时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能GPIOA的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //使能GPIOB的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); //使能GPIOC的时钟
//配置PB13(OLED_SCK)
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //设置引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //设置模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置I/O输出速度
GPIO_Init(GPIOA, &GPIO_InitStructure); //根据参数初始化GPIO
GPIO_SetBits(GPIOA, GPIO_Pin_5); //设置初始状态为高电平
//配置PB15(OLED_DIN)
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7; //设置引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //设置模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置I/O输出速度
GPIO_Init(GPIOA, &GPIO_InitStructure); //根据参数初始化GPIO
GPIO_SetBits(GPIOA, GPIO_Pin_7); //设置初始状态为高电平
//配置PB14(OLED_RES)
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; //设置引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //设置模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置I/O输出速度
GPIO_Init(GPIOA, &GPIO_InitStructure); //根据参数初始化GPIO
GPIO_SetBits(GPIOA, GPIO_Pin_6); //设置初始状态为高电平
//配置PB12(OLED_CS)
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; //设置引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //设置模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置I/O输出速度
GPIO_Init(GPIOA, &GPIO_InitStructure); //根据参数初始化GPIO
GPIO_SetBits(GPIOA, GPIO_Pin_4); //设置初始状态为高电平
//配置PC3(OLED_DC)
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11; //设置引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //设置模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置I/O输出速度
GPIO_Init(GPIOB, &GPIO_InitStructure); //根据参数初始化GPIO
GPIO_SetBits(GPIOB, GPIO_Pin_11); //设置初始状态为高电平
//配置Vcc
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //设置引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //设置模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置I/O输出速度
GPIO_Init(GPIOB, &GPIO_InitStructure); //根据参数初始化GPIO
GPIO_SetBits(GPIOB, GPIO_Pin_0); //设置初始状态为高电平
//配置Gnd
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; //设置引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //设置模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置I/O输出速度
GPIO_Init(GPIOB, &GPIO_InitStructure); //根据参数初始化GPIO
GPIO_ResetBits(GPIOB, GPIO_Pin_1); //设置初始状态为高电平
}
/*********************************************************************************************************
* 函数名称:ConfigOLEDReg
* 函数功能:配置OLED的寄存器
* 输入参数:void
* 输出参数:void
* 返 回 值:void
* 创建日期:2018年01月01日
* 注 意:
*********************************************************************************************************/
static void ConfigOLEDReg( void )
{
OLEDWriteByte(0xAE, OLED_CMD); //关闭显示
OLEDWriteByte(0xD5, OLED_CMD); //设置时钟分频因子,振荡频率
OLEDWriteByte(0x50, OLED_CMD); //[3:0]为分频因子,[7:4]为振荡频率
OLEDWriteByte(0xA8, OLED_CMD); //设置驱动路数
OLEDWriteByte(0x3F, OLED_CMD); //默认0x3F(1/64)
OLEDWriteByte(0xD3, OLED_CMD); //设置显示偏移
OLEDWriteByte(0x00, OLED_CMD); //默认为0
OLEDWriteByte(0x40, OLED_CMD); //设置显示开始行,[5:0]为行数
OLEDWriteByte(0x8D, OLED_CMD); //设置电荷泵
OLEDWriteByte(0x14, OLED_CMD); //bit2用于设置开启(1)/关闭(0)
OLEDWriteByte(0x20, OLED_CMD); //设置内存地址模式
OLEDWriteByte(0x02, OLED_CMD); //[1:0],00-列地址模式,01-行地址模式,10-页地址模式(默认值)
OLEDWriteByte(0xA1, OLED_CMD); //设置段重定义,bit0为0,列地址0->SEG0,bit0为1,列地址0->SEG127
OLEDWriteByte(0xC0, OLED_CMD); //设置COM扫描方向,bit3为0,普通模式,bit3为1,重定义模式
OLEDWriteByte(0xDA, OLED_CMD); //设置COM硬件引脚配置
OLEDWriteByte(0x12, OLED_CMD); //[5:4]为硬件引脚配置信息
OLEDWriteByte(0x81, OLED_CMD); //设置对比度
OLEDWriteByte(0xEF, OLED_CMD); //1~255,默认为0x7F(亮度设置,越大越亮)
OLEDWriteByte(0xD9, OLED_CMD); //设置预充电周期
OLEDWriteByte(0xf1, OLED_CMD); //[3:0]为PHASE1,[7:4]为PHASE2
OLEDWriteByte(0xDB, OLED_CMD); //设置VCOMH电压倍率
OLEDWriteByte(0x00, OLED_CMD); //[6:4],000-0.65*vcc,001-0.77*vcc,011-0.83*vcc
OLEDWriteByte(0xA4, OLED_CMD); //全局显示开启,bit0为1,开启,bit0为0,关闭
OLEDWriteByte(0xA6, OLED_CMD); //设置显示方式,bit0为1,反相显示,bit0为0,正常显示
OLEDWriteByte(0xAF, OLED_CMD); //开启显示
}
/*********************************************************************************************************
* 函数名称:CalcPow
* 函数功能:计算m的n次方
* 输入参数:m,n
* 输出参数:void
* 返 回 值:m的n次方结果
* 创建日期:2018年01月01日
* 注 意:
*********************************************************************************************************/
static u32 CalcPow(u8 m, u8 n)
{
u32 result = 1; //定义用来存放结果的变量
while(n--) //随着每次循环,n递减,直至为0
{
result *= m; //循环n次,相当于n个m相乘
}
return result; //返回m的n次幂的值
}
/*********************************************************************************************************
* API函数实现
*********************************************************************************************************/
/*********************************************************************************************************
* 函数名称:InitOLED
* 函数功能:初始化OLED模块
* 输入参数:void
* 输出参数:void
* 返 回 值:void
* 创建日期:2018年01月01日
* 注 意:
*********************************************************************************************************/
void InitOLED(void)
{
ConfigOLEDGPIO(); //配置OLED的GPIO
CLR_OLED_RES();
DelayNms(10);
SET_OLED_RES(); //RES引脚务必拉高
DelayNms(10);
ConfigOLEDReg(); //配置OLED的寄存器
OLEDClear(); //清除OLED屏内容
OLEDRefreshGRAM();
}
/*********************************************************************************************************
* 函数名称:OLEDDisplayOn
* 函数功能:开启OLED显示
* 输入参数:void
* 输出参数:void
* 返 回 值:void
* 创建日期:2018年01月01日
* 注 意:
*********************************************************************************************************/
void OLEDDisplayOn( void )
{
//打开关闭电荷泵,第一个字节为命令字,0x8D,第二个字节设置值,0x10-关闭电荷泵,0x14-打开电荷泵
OLEDWriteByte(0x8D, OLED_CMD); //第一个字节0x8D为命令
OLEDWriteByte(0x14, OLED_CMD); //0x14-打开电荷泵
//设置显示开关,0xAE-关闭显示,0xAF-开启显示
OLEDWriteByte(0xAF, OLED_CMD); //开启显示
}
/*********************************************************************************************************
* 函数名称:OLEDDisplayOff
* 函数功能:关闭OLED显示
* 输入参数:void
* 输出参数:void
* 返 回 值:void
* 创建日期:2018-01-01
* 注 意:
*********************************************************************************************************/
void OLEDDisplayOff( void )
{
//打开关闭电荷泵,第一个字节为命令字,0x8D,第二个字节设置值,0x10-关闭电荷泵,0x14-打开电荷泵
OLEDWriteByte(0x8D, OLED_CMD); //第一个字节为命令字,0x8D
OLEDWriteByte(0x10, OLED_CMD); //0x10-关闭电荷泵
//设置显示开关,0xAE-关闭显示,0xAF-开启显示
OLEDWriteByte(0xAE, OLED_CMD); //关闭显示
}
/*********************************************************************************************************
* 函数名称:OLEDRefreshGRAM
* 函数功能:将STM32的GRAM写入到SSD1306的GRAM
* 输入参数:void
* 输出参数:void
* 返 回 值:void
* 创建日期:2018年01月01日
* 注 意:
*********************************************************************************************************/
void OLEDRefreshGRAM(void)
{
u8 i;
u8 n;
for(i = 0; i < 8; i++) //遍历每一页
{
OLEDWriteByte(0xb0 + i, OLED_CMD); //设置页地址(0~7)
OLEDWriteByte(0x00, OLED_CMD); //设置显示位置—列低地址
OLEDWriteByte(0x10, OLED_CMD); //设置显示位置—列高地址
for(n = 0; n < 132; n++) //遍历每一列
{
//通过循环将STM32的GRAM写入到SSD1306的GRAM
OLEDWriteByte(s_arrOLEDGRAM[n][i], OLED_DATA);
}
}
}
/*********************************************************************************************************
* 函数名称:OLEDClear
* 函数功能:清屏函数,清完屏整个屏幕是黑色的,和没点亮一样
* 输入参数:void
* 输出参数:void
* 返 回 值:void
* 创建日期:2018年01月01日
* 注 意:
*********************************************************************************************************/
void OLEDClear(void)
{
u8 i;
u8 n;
for(i = 0; i < 8; i++) //遍历每一页
{
for(n = 0; n < 132; n++) //遍历每一列
{
s_arrOLEDGRAM[n][i] = 0x00; //将指定点清零
}
}
}
/*********************************************************************************************************
* 函数名称:OLEDWriteByte
* 函数功能:向SSD1306写入一个字节
* 输入参数:dat为要写入的数据或命令,cmd为数据/命令标志,0-命令,1-数据
* 输出参数:void
* 返 回 值:void
* 创建日期:2018年01月01日
* 注 意:
*********************************************************************************************************/
void OLEDWriteByte(u8 dat, u8 cmd)
{
i16 i;
//判断要写入数据还是写入命令
if(OLED_CMD == cmd) //如果标志cmd为传入命令时
{
CLR_OLED_DC(); //DC输出低电平用来读写命令
}
else if(OLED_DATA == cmd) //如果标志cmd为传入数据时
{
SET_OLED_DC(); //DC输出高电平用来读写数据
}
CLR_OLED_CS(); //CS输出低电平为写入数据或命令作准备
for(i = 0; i < 8; i++) //循环8次,从高到低取出要写入的数据或命令的8个bit
{
CLR_OLED_SCK(); //SCK输出低电平为写入数据作准备
if(dat & 0x80) //判断要写入的数据或命令的最高位是1还是0
{
SET_OLED_DIN(); //要写入的数据或命令的最高位是1,DIN输出高电平表示1
}
else
{
CLR_OLED_DIN(); //要写入的数据或命令的最高位是0,DIN输出低电平表示0
}
SET_OLED_SCK(); //SCK输出高电平,DIN的状态不再变化,此时写入数据线的数据
dat <<= 1; //左移一位,次高位移到最高位
}
SET_OLED_CS(); //OLED的CS输出高电平,不再写入数据或命令
SET_OLED_DC(); //OLED的DC输出高电平
}
/*********************************************************************************************************
* 函数名称:OLEDDrawPoint
* 函数功能:在指定位置画点
* 输入参数:x取值范围为0~127,y取值范围为0~63,t为1表示填充,t为0表示清空
* 输出参数:void
* 返 回 值:void
* 创建日期:2018年01月01日
* 注 意:(1)x-y轴体系的原点坐标在屏幕左上角;
* (2)物理显示的y与SSD1306显存的COMn的n相加为63,当然,屏幕的行号(按字节)与SSD1306的行号(按
* 字节)相加为7。
*********************************************************************************************************/
void OLEDDrawPoint(u8 x, u8 y, u8 t)
{
u8 pos; //存放点所在的页数
u8 bx; //存放点所在的屏幕的行号
u8 temp = 0; //用来存放画点位置相对于字节的位
if(x > 127 || y > 63) //如果指定位置超过额定范围
{
return; //返回空,函数结束
}
pos = 7 - y / 8; //求指定位置所在页数
bx = y % 8; //求指定位置在上面求出页数中的行号
temp = 1 << (7 - bx); //(7-bx)求出相应SSD1306的行号,并在字节中相应的位置为1
if(t) //判断填充标志为1还是0
{
s_arrOLEDGRAM[x][pos] |= temp; //如果填充标志为1,指定点填充
}
else
{
s_arrOLEDGRAM[x][pos] &= ~temp; //如果填充标志为0,指定点清空
}
}
/*********************************************************************************************************
* 函数名称:OLEDShowChar
* 函数功能:在指定位置显示一个字符
* 输入参数:x取值范围为0~127,y取值范围为0~63,chr为待显示的字符,size用于选择字体(16/12),mode为取模方式
* mode为0反白显示,mode为1正常显示
* 输出参数:void
* 返 回 值:void
* 创建日期:2018年01月01日
* 注 意:有6种取模方式
*********************************************************************************************************/
void OLEDShowChar(u8 x, u8 y, u8 chr, u8 size, u8 mode)
{
u8 temp; //用来存放字符顺向逐列式的相对位置
u8 t1; //循环计数器1
u8 t2; //循环计数器2
u8 y0 = y; //当前操作的行数
chr = chr - ' '; //得到相对于空格(ASCII为0x20)的偏移值,求出要chr在数组中的索引
for(t1 = 0; t1 < size; t1++) //循环逐列显示
{
if(size == 12) //判断字号大小,选择相对的顺向逐列式
{
temp = g_iASCII1206[chr][t1]; //取出字符在g_iASCII1206数组中的第t1列
}
else
{
temp = g_iASCII1608[chr][t1]; //取出字符在g_iASCII1608数组中的第t1列
}
for(t2 = 0; t2 < 8; t2++) //在一个字符的第t2列的横向范围(8个像素)内显示点
{
if(temp & 0x80) //取出temp的最高位,并判断为0还是1
{
OLEDDrawPoint(x, y, mode); //如果temp的最高位为1填充指定位置的点
}
else
{
OLEDDrawPoint(x, y, !mode); //如果temp的最高位为0清除指定位置的点
}
temp <<= 1; //左移一位,次高位移到最高位
y++; //进入下一行
if((y - y0) == size) //如果显示完一列
{
y = y0; //行号回到原来的位置
x++; //进入下一列
break; //跳出上面带#的循环
}
}
}
}
/*********************************************************************************************************
* 函数名称:OLEDShowNum
* 函数功能:显示数字
* 输入参数:x-y为起点坐标,len为数字的位数,size为字体大小,mode为模式(0-填充模式,1-叠加模式)
* 输出参数:void
* 返 回 值:void
* 创建日期:2018年01月01日
* 注 意:num:数值(0~4294967295)
*********************************************************************************************************/
void OLEDShowNum(u8 x, u8 y, u32 num, u8 len, u8 size)
{
u8 t; //循环计数器
u8 temp; //用来存放要显示数字的各个位
u8 enshow = 0; //区分0是否为高位0标志位
for(t = 0; t < len; t++)
{
temp = (num / CalcPow(10, len - t - 1) ) % 10; //按从高到低取出要显示数字的各个位,存到temp中
if(enshow == 0 && t < (len - 1)) //如果标记enshow为0并且还未取到最后一位
{
if(temp == 0 ) //如果temp等于0
{
OLEDShowChar(x + (size / 2) * t, y, '0', size, 1); //此时的0在高位,用空格替代
continue; //提前结束本次循环,进入下一次循环
}
else
{
enshow = 1; //否则将标记enshow置为1
}
}
OLEDShowChar(x + (size / 2) * t, y, temp + '0', size, 1); //在指定位置显示得到的数字
}
}
/*********************************************************************************************************
* 函数名称:OLEDShowString
* 函数功能:显示字符串
* 输入参数:x-y为起点坐标,p为字符串起始地址
* 输出参数:void
* 返 回 值:void
* 创建日期:2018年01月01日
* 注 意:用16号字体显示
*********************************************************************************************************/
void OLEDShowString(u8 x, u8 y, const u8* p)
{
#define MAX_CHAR_POSX 122 //OLED屏幕横向的最大范围
#define MAX_CHAR_POSY 58 //OLED屏幕纵向的最大范围
while(*p != '\0') //指针不等于结束符时,循环进入
{
if(x > MAX_CHAR_POSX) //如果x超出指定最大范围,x赋值为0
{
x = 0;
y += 16; //显示到下一行左端
}
if(y > MAX_CHAR_POSY) //如果y超出指定最大范围,x和y均赋值为0
{
y = x = 0; //清除OLED屏幕内容
OLEDClear(); //显示到OLED屏幕左上角
OLEDRefreshGRAM();
}
OLEDShowChar(x, y, *p, 16, 1); //指定位置显示一个字符
x += 8; //一个字符横向占8个像素点
p++; //指针指向下一个字符
}
}
/*********************************************************************************************************
* 函数名称:OLEDShowChinese
* 函数功能:显示汉字
* 输入参数:x-y为起点坐标,p为字符串起始地址
* 输出参数:void
* 返 回 值:void
* 创建日期:2018年01月01日
* 注 意:用16号字体显示
*********************************************************************************************************/
void OLEDShowChinese(u8 x,u8 y,u8 chinese[][32],u8 chr,u8 size,u8 mode)
{
u8 temp; //用来存放字符顺向逐列式的相对位置
u8 t1; //循环计数器1
u8 t2; //循环计数器2
u8 t3;
u8 y0=y; //当前操作的行数
for(t3=0;t3<chr;t3++)
{
for(t1=0;t1<size*2;t1++) //循行逐列显示
{
temp=chinese[t3][t1];
for(t2=0;t2<8;t2++) //在一个字符的第t2列的横向范围(8像素)内显示点
{
if(temp&0x80) //取出temp的最高位,并判断是0还是1
{
OLEDDrawPoint(x,y,mode); //如果temp最高位是1,填充指定位置的点
}
else
{
OLEDDrawPoint(x,y,!mode); //如果temp最高位是0,清除指定位置的点
}
temp<<=1; //左移一位,次高位移到最高位
y++; //进入下一行
if((y-y0)==size) //如果显示完一列
{
y=y0; //行号回到原来的位置
x++; //进入下一列
break; //跳出循环
}
}
}
}
//OLEDRefreshGRAM();
}
/*********************************************************************************************************
* 函数名称:OLEDShowPicture
* 函数功能:显示32*32图片
* 输入参数:x-y为起点坐标,
* 输出参数:void
* 返 回 值:void
* 创建日期:2018年01月01日
* 注 意:用16号字体显示
*********************************************************************************************************/
void OLEDShowPicture(u8 x,u8 y,u8 picture[],u8 mode)
{
u8 i=0;
u8 t1;
u8 t2;
u8 t3;
u8 temp;
for(t1=x ;t1<x+32; t1++)
{
for(t2=0 ;t2<4 ;t2++)
{
temp = picture[i];
for(t3=0 ;t3<8 ;t3++)
{
if(temp&0x80) //取出temp的最高位,并判断是0还是1
{
OLEDDrawPoint(t1,y+t2*8+t3,mode); //如果temp最高位是1,填充指定位置的点
}
else
{
OLEDDrawPoint(t1,y+t2*8+t3,!mode); //如果temp最高位是0,清除指定位置的点
}
temp<<=1; //左移一位,次高位移到最高位
}
i++;
}
}
}
OLED这里没啥好说的,都是固定的东西,改一改就适配了,只适配SPI通信的OLED
代码四、
/*********************************************************************************************************
* 模块名称:CalcPWM.c
* 摘 要:CalcPWM模块
* 当前版本:1.0.0
* 作 者:SZLY(COPYRIGHT 2018 - 2020 SZLY. All rights reserved.)
* 完成日期:2020年01月01日
* 内 容:
* 注 意:
**********************************************************************************************************
* 取代版本:
* 作 者:
* 完成日期:
* 修改内容:
* 修改文件:
*********************************************************************************************************/
/*********************************************************************************************************
* 包含头文件
*********************************************************************************************************/
#include "LED.h"
#include "stm32f10x_conf.h"
#include "PWM.h"
#include "KEY.h"
#include "ADC.h"
#include "OLED.h"
#include "rang.h"
#include "SysTick.h"
#include "bsp_i2c.h"
/*********************************************************************************************************
* 宏定义
*********************************************************************************************************/
/*********************************************************************************************************
* 枚举结构体定义
*********************************************************************************************************/
/*********************************************************************************************************
* 内部变量
*********************************************************************************************************/
extern uint16_t key_val;
static u8 num;
static u8 num2;
static u8 key = 0;
static u8 number[7][32] = {
{0x08,0x20,0x30,0x20,0xA0,0x40,0xAA,0x50,0xAA,0x90,0xAA,0x94,0xA1,0x54,0xFE,0x32,0xA1,0x12,0xAA,0x95,0xAA,0x98,0xAA,0x40,0xA0,0x40,0x28,0x20,0x30,0x20,0x00,0x00},/*"零",0*/
{0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x00,0x00},/*"一",0*/
{0x00,0x08,0x00,0x08,0x10,0x08,0x10,0x08,0x10,0x08,0x10,0x08,0x10,0x08,0x10,0x08,0x10,0x08,0x10,0x08,0x10,0x08,0x10,0x08,0x10,0x08,0x00,0x08,0x00,0x08,0x00,0x00},/*"二",1*/
{0x00,0x04,0x20,0x04,0x21,0x04,0x21,0x04,0x21,0x04,0x21,0x04,0x21,0x04,0x21,0x04,0x21,0x04,0x21,0x04,0x21,0x04,0x21,0x04,0x21,0x04,0x20,0x04,0x00,0x04,0x00,0x00},/*"三",2*/
{0x00,0x00,0x3F,0xFE,0x20,0x14,0x20,0x24,0x20,0xC4,0x3F,0x04,0x20,0x04,0x20,0x04,0x20,0x04,0x3F,0x84,0x20,0x44,0x20,0x44,0x20,0x44,0x3F,0xFE,0x00,0x00,0x00,0x00},/*"四",3*/
{0x00,0x02,0x40,0x02,0x42,0x02,0x42,0x02,0x42,0x1E,0x43,0xE2,0x7E,0x02,0x42,0x02,0x42,0x02,0x42,0x02,0x42,0x02,0x43,0xFE,0x40,0x02,0x40,0x02,0x00,0x02,0x00,0x00},/*"五",4*/
};
static u8 mode[6][32] = {
{0x00,0x40,0x00,0x40,0x24,0x40,0x24,0x40,0x24,0x40,0x24,0x42,0x24,0x41,0x3F,0xFE,0x44,0x40,0x44,0x40,0x44,0x40,0xC4,0x40,0x44,0x40,0x00,0x40,0x00,0x40,0x00,0x00},/*"手",0*/
{0x02,0x08,0x22,0x3C,0x23,0xC8,0x22,0x08,0x22,0x28,0x22,0x1D,0x02,0x02,0x08,0x0C,0x08,0x70,0xFF,0x80,0x08,0x02,0x08,0x01,0x08,0x02,0x0F,0xFC,0x00,0x00,0x00,0x00},/*"动",1*/
{0x02,0x00,0x42,0x00,0x33,0xFE,0x00,0x04,0x00,0x08,0x41,0x00,0x49,0x3F,0x49,0x22,0x4F,0x22,0x79,0x22,0x49,0x22,0x49,0x22,0x4F,0x3F,0x41,0x00,0x01,0x00,0x00,0x00},/*"语",0*/
{0x02,0x00,0x02,0x00,0x22,0x00,0x22,0xFF,0x2A,0x92,0x26,0x92,0xA2,0x92,0x62,0x92,0x22,0x92,0x26,0x92,0x2A,0x92,0x22,0xFF,0x22,0x00,0x02,0x00,0x02,0x00,0x00,0x00},/*"音",1*/
{0x08,0x20,0x06,0x20,0x40,0x7E,0x31,0x80,0x00,0x02,0x00,0x7E,0x7F,0x42,0x49,0x42,0x49,0x7E,0x49,0x42,0x49,0x7E,0x49,0x42,0x7F,0x42,0x00,0x7E,0x00,0x02,0x00,0x00},/*"温",2*/
{0x08,0x40,0x08,0x42,0x08,0x81,0xFF,0xFE,0x09,0x00,0x04,0x02,0x19,0x02,0x12,0x42,0x14,0x42,0x90,0x42,0x70,0x7E,0x14,0x42,0x12,0x42,0x15,0x42,0x18,0x02,0x00,0x00},/*"控",3*/
};
// ADC1转换的电压值通过MDA方式传到SRAM
extern __IO uint16_t ADC_ConvertedValue[NOFCHANEL];
// 局部变量,用于保存转换计算后的电压值
float ADC_ConvertedValueLocal[NOFCHANEL];
float length; //测量的距离
extern uint32_t H1; //Humility
extern uint32_t T1; //Temperature
/*********************************************************************************************************
* 内部函数声明
*********************************************************************************************************/
//static void voiceCheck(void); //语音控制
static void keyCheck(void); //按键控制
static void rangeCheck(void); //测距控制
static void TemparetureCheck(void); //温度控制
static void PWMControl(u8 number); //pwm的控制
/*********************************************************************************************************
* 内部函数实现
*********************************************************************************************************/
/*********************************************************************************************************
* 函数名称:voiceCheck
* 函数功能:语音控制
* 输入参数:void
* 输出参数:void
* 返 回 值:void
* 创建日期:2018年01月01日
* 注 意:
*********************************************************************************************************/
//static void voiceCheck(void)
//{
// ADC_ConvertedValueLocal[0] =(float) ADC_ConvertedValue[0]/4096*3.3;
// ADC_ConvertedValueLocal[1] =(float) ADC_ConvertedValue[1]/4096*3.3;
// ADC_ConvertedValueLocal[2] =(float) ADC_ConvertedValue[2]/4096*3.3;
// if(ADC_ConvertedValueLocal[0] > 1.6 && ADC_ConvertedValueLocal[1] < 1.6 && ADC_ConvertedValueLocal[2] < 1.6) /*001 一档*/
// {
// key = 1;
// num = 1;
// }
// else if(ADC_ConvertedValueLocal[0] < 1.6 && ADC_ConvertedValueLocal[1] > 1.6 && ADC_ConvertedValueLocal[2] < 1.6) /*010 二挡*/
// {
// key = 1;
// num = 2;
// }
// else if(ADC_ConvertedValueLocal[0] > 1.6 && ADC_ConvertedValueLocal[1] > 1.6 && ADC_ConvertedValueLocal[2] < 1.6) /*011 三档*/
// {
// key = 1;
// num = 3;
// }
// else if(ADC_ConvertedValueLocal[0] < 1.6 && ADC_ConvertedValueLocal[1] < 1.6 && ADC_ConvertedValueLocal[2] > 1.6) /*100 四挡*/
// {
// key = 1;
// num = 4;
// }
// else if(ADC_ConvertedValueLocal[0] > 1.6 && ADC_ConvertedValueLocal[1] < 1.6 && ADC_ConvertedValueLocal[2] > 1.6) /*101 五档*/
// {
// key = 1;
// num = 5;
// }
// else if(ADC_ConvertedValueLocal[0] > 1.6 && ADC_ConvertedValueLocal[1] > 1.6 && ADC_ConvertedValueLocal[2] > 1.6) /*111 开风扇*/
// {
// key = 1;
// num = num;
// }
// else if(ADC_ConvertedValueLocal[0] < 1.6 && ADC_ConvertedValueLocal[1] < 1.6 && ADC_ConvertedValueLocal[2] < 1.6) /*000 关风扇*/
// {
// key = 0;
// num = 0;
// SetPWM(0);
// }
//}
static void keyCheck(void) //按键控制
{
if(keyboard_scan() == 1) //按键1,增加档位
{
key_val = 0; //按下后不再受到按键的影响
num++;
if(num > 5)
{
num = 5;
}
}
else if(keyboard_scan() == 2) //按键2,减小档位
{
key_val = 0;
num--;
if(num < 1)
{
num = 0;
}
}
else if(keyboard_scan() == 3) //按键3,风扇的开关
{
static u8 num1;
key_val = 0;
num1++;
if(num1 > 2)
{
num1 = 1;
}
if(num1 == 1)
{
key = 1;
num = num;
}
else if(num1 == 2)
{
key = 0;
num = 0;
SetPWM(0);
}
}
else if(keyboard_scan() == 16)
{
key = 0;
num = 0;
}
}
static void rangeCheck(void) //测距控制
{
length = HCSR04GetLength();
DelayNms(500);
if(length > 60.00)
{
num = 0;
}
else
{
num = num;
}
}
static void TemparetureCheck(void) //温度控制
{
DelayNms(500);
if(T1 < 27.0)
{
num = 0;
}
else if(T1 > 27.0 && T1 < 27.5)
{
num = 1;
}
else if(T1 >= 27.5 && T1 < 28.0)
{
num = 2;
}
else if(T1 >= 28.0 && T1 < 28.5)
{
num = 3;
}
else if(T1 >= 28.5 && T1 < 29.0)
{
num = 4;
}
else if(T1 >= 29.0 && T1 < 30.0)
{
num = 5;
}
else if(T1 > 30.0)
{
num = 5;
}
}
static void PWMControl(u8 numb) //pwm的控制
{
if(key == 1)
{
OLEDShowString(4,0," ");
OLEDShowString(4,0,"ON");
SetPWM(numb * 100);
}
else
{
OLEDShowString(4,0," ");
OLEDShowString(4,0,"OFF");
}
switch(numb)
{
case 1:OLEDShowChinese(52,17,&number[1],1,16,1);break;
case 2:OLEDShowChinese(52,17,&number[2],1,16,1);break;
case 3:OLEDShowChinese(52,17,&number[3],1,16,1);break;
case 4:OLEDShowChinese(52,17,&number[4],1,16,1);break;
case 5:OLEDShowChinese(52,17,&number[5],1,16,1);break;
default:OLEDShowChinese(52,17,&number[0],1,16,1);break;
}
OLEDRefreshGRAM();
}
/*********************************************************************************************************
* API函数实现
*********************************************************************************************************/
/*********************************************************************************************************
* 函数名称:CalcPWM
* 函数功能:通过按键,语音模块、温度变化等方法改变输出的PWM模块
* 输入参数:void
* 输出参数:void
* 返 回 值:void
* 创建日期:2018年01月01日
* 注 意:
*********************************************************************************************************/
void CalcPWM(void)
{
if(keyboard_scan() == 4)
{
num2++;
if(num2 > 1)
{
num2 = 0;
}
}
if(num2 == 0)
{
key_val = 0;
keyCheck();
OLEDShowChinese(70,17,&mode[0],1,16,1);
OLEDShowChinese(86,17,&mode[1],1,16,1);
}
else if(num2 == 1)
{
key_val = 0;
// voiceCheck();
OLEDShowChinese(70,17,&mode[2],1,16,1);
OLEDShowChinese(86,17,&mode[3],1,16,1);
}
// else if(num2 == 2)
// {
// key_val = 0;
// TemparetureCheck();
// OLEDShowChinese(70,17,&mode[4],1,16,1);
// OLEDShowChinese(86,17,&mode[5],1,16,1);
// }
// read_AHT20_once();
// rangeCheck();
PWMControl(num);
// OLEDShowString(4,48,"Length:");
// OLEDShowNum(60,52,(int)length,2,12);
// OLEDShowChar(74,52,'.',12,1);
// OLEDShowNum(82,52,(int)(length * 100) % 100,2,12);
// OLEDShowString(100,48,"cm");
}
这里是改变PWM波的控制中心,附加了其他的模块代码,不删了,接其他模块的时候可以使用。
最后一个代码就是PWM的配置了。
/*********************************************************************************************************
* 模块名称:PWM.c
* 摘 要:PWM模块
* 当前版本:1.0.0
* 作 者:SZLY(COPYRIGHT 2018 - 2020 SZLY. All rights reserved.)
* 完成日期:2020年01月01日
* 内 容:
* 注 意:
**********************************************************************************************************
* 取代版本:
* 作 者:
* 完成日期:
* 修改内容:
* 修改文件:
*********************************************************************************************************/
/*********************************************************************************************************
* 包含头文件
*********************************************************************************************************/
#include "PWM.h"
#include "stm32f10x.h"
/*********************************************************************************************************
* 宏定义
*********************************************************************************************************/
/*********************************************************************************************************
* 枚举结构体定义
*********************************************************************************************************/
/*********************************************************************************************************
* 内部变量
*********************************************************************************************************/
i16 s_iDutyCycle = 0; //用于存放占空比值
/*********************************************************************************************************
* 内部函数声明
*********************************************************************************************************/
static void ConfigTimer3ForPWMPB5(u16 arr,u16 psc); //配置PWM
/*********************************************************************************************************
* 内部函数实现
*********************************************************************************************************/
/*********************************************************************************************************
* 函数名称:ConfigTimer3ForPWMPB5
* 函数功能:配置PWM
* 输入参数:u16 arr,u16 psc
* 输出参数:void
* 返 回 值:void
* 创建日期:2018年01月01日
* 注 意:
*********************************************************************************************************/
static void ConfigTimer3ForPWMPB5(u16 arr,u16 psc)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
//使能RCC相关时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
//注意,GPIO
GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3,ENABLE); //TIM3部分重映射TIM3.CH2->PB5
//配置PB5,对应TIM3的CH2
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStructure);
//配置TIM3
TIM_TimeBaseStructure.TIM_Period = arr;
TIM_TimeBaseStructure.TIM_Prescaler = psc;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //设置递增计数模式
TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStructure); //根据参数初始化TIM3
//配置TIM3的CH2为PWM模式,在TIM_CounterMode_Up模式下,TIMx_CNT < TIMx_CCRx时为无效电平(高电平)
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //设置为PWM2模式
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //使能比较输出
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; //设置极性,OC2低电平有效
TIM_OC2Init(TIM3,&TIM_OCInitStructure); //根据参数初始化TIM3的CH2
TIM_OC2PreloadConfig(TIM3,TIM_OCPreload_Enable); //使能TIM3的CH2预装载
TIM_Cmd(TIM3,ENABLE); //使能TIM3
}
/*********************************************************************************************************
* API函数实现
*********************************************************************************************************/
/*********************************************************************************************************
* 函数名称:InitPWM
* 函数功能:初始化PWM
* 输入参数:void
* 输出参数:void
* 返 回 值:void
* 创建日期:2018年01月01日
* 注 意:
*********************************************************************************************************/
void InitPWM(void)
{
ConfigTimer3ForPWMPB5(599,999); //配置TIM3,72000000/(999+1)/(599+1) = 120Hz
TIM_SetCompare2(TIM3,0); //设置初始值为0
}
/*********************************************************************************************************
* 函数名称:SetPWM
* 函数功能:设置PWM
* 输入参数:i16 val
* 输出参数:void
* 返 回 值:void
* 创建日期:2018年01月01日
* 注 意:
*********************************************************************************************************/
void SetPWM(i16 val) //设置PWM
{
s_iDutyCycle = val; //获取占空比的值
TIM_SetCompare2(TIM3,s_iDutyCycle); //设置占空比
}
/*********************************************************************************************************
* 函数名称:IncPWMDutyCycle
* 函数功能:增加PWM
* 输入参数:void
* 输出参数:void
* 返 回 值:void
* 创建日期:2018年01月01日
* 注 意:
*********************************************************************************************************/
void IncPWMDutyCycle(void) //增加PWM
{
if(s_iDutyCycle >= 600)
{
s_iDutyCycle = 600;
}
else
{
s_iDutyCycle += 100;
}
TIM_SetCompare2(TIM3,s_iDutyCycle);
}
/*********************************************************************************************************
* 函数名称:DecPWMDutyCycle
* 函数功能:减少PWM
* 输入参数:void
* 输出参数:void
* 返 回 值:void
* 创建日期:2018年01月01日
* 注 意:
*********************************************************************************************************/
void DecPWMDutyCycle(void) //减少PWM
{
if(s_iDutyCycle <= 0)
{
s_iDutyCycle = 0;
}
else
{
s_iDutyCycle -= 100;
}
TIM_SetCompare2(TIM3,s_iDutyCycle); //设置占空比
}
当然了,这里也是标准配置,自己研究研究就会了。前提是知道啥是PWM
四、成品
https://www.bilibili.com/video/BV1cu411t7Kt/?vd_source=de78c9e88a60b2bce782148bbf8657b2
转自:https://blog.csdn.net/qq_48824303/article/details/130631887