前言
上一期后面我们简单的介绍了stc的进阶开发,点亮LED灯,这期我们继续向下学习,学一学PWM,PWM是什么呢?PWM又能实现什么功能呢?带着这些疑惑,我们开启今天的学习。
LED8路呼吸灯
PWM进本概念
PWM全称是脉宽调制(Pulse Width Modulation),是一种通过改变信号的脉冲宽度来控制电路输出的技术。PWM技术在工业自动化、电机控制、LED调光等领域广泛应用。
PWM是一种将数字信号转换为模拟信号的技术,它通过改变信号的占空比来控制输出的电平。在STC8H中,PWM输出的频率和占空比可以由程序控制,因此可以用来控制各种电机、灯光和其他设备的亮度、速度等参数。
STC8H芯片
STC8H 系列的单片机内部集成了8 通道 16 位高级PWM 定时器,分成两周期可不同的 PWM,分别命名为 PWMA 和PWMB ,可分别单独设置。第一组 PWMA 可配置成4 组互补/对称/死区控制的PWM 或捕捉外部信号。第二组 PWMB 可配置成4 路PWM 输出或捕捉外部信号。两组 PWM 的时钟频率可分别独立设置。
用PWM控制LED灯
这里我们先来展示一个简单代码,主要配置PWM环境,代码解析请直接看代码中的注释,代码如下:
#include "GPIO.h"
#include "NVIC.h"
#include "Switch.h"
#include "STC8H_PWM.h"
#include "delay.h"
#define LED_SW P45
#define LED1 P27
#define LED2 P26
#define LED3 P15
#define LED4 P14
#define LED5 P23
#define LED6 P22
#define LED7 P21
#define LED8 P20
void GPIO_Config(){
//1. LED_SW
GPIO_InitTypeDef GPIO_InitStructure; //结构定义
GPIO_InitStructure.Pin = GPIO_Pin_5; //指定要初始化的IO,
GPIO_InitStructure.Mode = GPIO_OUT_PP; //指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP
GPIO_Inilize(GPIO_P4, &GPIO_InitStructure);//初始化
//2. LED1-LED8
GPIO_InitStructure.Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_6 | GPIO_Pin_7; //指定要初始化的IO,
GPIO_InitStructure.Mode = GPIO_OUT_PP; //指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP
GPIO_Inilize(GPIO_P2, &GPIO_InitStructure);//初始化
GPIO_InitStructure.Pin = GPIO_Pin_4 | GPIO_Pin_5; //指定要初始化的IO,
GPIO_InitStructure.Mode = GPIO_OUT_PP; //指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP
GPIO_Inilize(GPIO_P1, &GPIO_InitStructure);//初始化
}
#define PERIOD MAIN_Fosc/1000
void PWM_Config(){
//1. 创建结构体变量
PWMx_InitDefine init;
//2. 给 成员赋值
init.PWM_Mode = CCMRn_PWM_MODE2; //模式, CCMRn_FREEZE,CCMRn_MATCH_VALID,CCMRn_MATCH_INVALID,CCMRn_ROLLOVER,CCMRn_FORCE_INVALID,CCMRn_FORCE_VALID,CCMRn_PWM_MODE1,CCMRn_PWM_MODE2
/*
1. 时钟主频: 24MHz , 意思就是1s中可以数这么数。
2. 在一个时间段内,计算高电平和低电平的占比.
2.1 1s可以数24000000 个数, 1000ms 可以数 24000000 个数。 1ms 可以数 24000 个数
2.2 使用时钟主频 /1000 即表示我们希望吧时间切割成1000份
2.3 即可以看成是 使用 1ms 来作为PWM的周期时间,在这1ms里面要有高电平和低电平.
3. 只是在这1ms里面的高电平和低电平的比例不一样。 由这个PWM_Duty来控制
*/
init.PWM_Period = PERIOD - 1; //周期时间, 0~65535 :: 24000 -1是因为计算机数数是从0开始数数
init.PWM_Duty = 0; //占空比时间, 0~Period 高电平占多少比例。
init.PWM_DeadTime = 0; //死区发生器设置, 0~255
init.PWM_EnoSelect = ENO4P | ENO4N; //输出通道选择, ENO1P,ENO1N,ENO2P,ENO2N,ENO3P,ENO3N,ENO4P,ENO4N / ENO5P,ENO6P,ENO7P,ENO8P
init.PWM_CEN_Enable = ENABLE; //使能计数器, ENABLE,DISABLE
init.PWM_MainOutEnable = ENABLE;//主输出使能, ENABLE,DISABLE
//3. 初始化PWM【需要对大类进行初始化,也需要对小组进行初始化】
PWM_Configuration(PWM4, &init);
PWM_Configuration(PWMA, &init);
//4. 中断使能
NVIC_PWM_Init(PWMA , DISABLE , Priority_1);
//5. 切换使用引脚
PWM4_SW(PWM4_SW_P26_P27);
}
//创建占空比的结构体变量
PWMx_Duty duty;
void main(){
//定义一个比例值: 0 ~ 100;
int peicent = 50;
int direction = 1;
//打开外部扩展寄存器使能:: PWM 一定要打开这个开关
EAXSFR();
//0. 中断总开关
EA = 1 ;
//1. 配置IO
GPIO_Config();
//2. 配置PWM
PWM_Config();
//3. 打开LED的总开关
LED_SW = 0;
//4. 先让3个灯亮起来:: LED1 和 LED2 是互补的PWM ,所以一会应该会出现我亮,你不亮的情况。但是LED3没有使用PWM控制它,所以它一直常亮!
LED1 = LED2 = LED3 = 0;
while(1){
//先让percent往上+ ,一会到了100之后,就控制direction 成-1 ,就变成往下减的情况
peicent += direction;
if(peicent >= 100){
peicent = 100;
direction = -1;
}else if(peicent <= 0 ){
peicent = 0;
direction = 1;
}
//设置第4组的占空比。
duty.PWM4_Duty = PERIOD * peicent / 100 ;
//更新占空比:: 参数一更新哪一个组、大类的占空比 , 参数二就是更新具体哪一组的占空比
UpdatePwm(PWM4, &duty);
delay_ms(20);
}
}
用PWM控制8路呼吸灯
#include "GPIO.h"
#include "NVIC.h"
#include "Switch.h"
#include "STC8H_PWM.h"
#include "delay.h"
#include "UART.h"
#define LED_SW P45
#define LED1 P27
#define LED2 P26
#define LED3 P15
#define LED4 P14
#define LED5 P23
#define LED6 P22
#define LED7 P21
#define LED8 P20
void GPIO_Config(){
//1. LED_SW
GPIO_InitTypeDef GPIO_InitStructure; //结构定义
GPIO_InitStructure.Pin = GPIO_Pin_5; //指定要初始化的IO,
GPIO_InitStructure.Mode = GPIO_OUT_PP; //指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP
GPIO_Inilize(GPIO_P4, &GPIO_InitStructure);//初始化
//2. LED1-LED8
GPIO_InitStructure.Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_6 | GPIO_Pin_7; //指定要初始化的IO,
GPIO_InitStructure.Mode = GPIO_OUT_PP; //指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP
GPIO_Inilize(GPIO_P2, &GPIO_InitStructure);//初始化
GPIO_InitStructure.Pin = GPIO_Pin_4 | GPIO_Pin_5; //指定要初始化的IO,
GPIO_InitStructure.Mode = GPIO_OUT_PP; //指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP
GPIO_Inilize(GPIO_P1, &GPIO_InitStructure);//初始化
}
#define PERIOD MAIN_Fosc / 1000
void PWM_Config(){
PWMx_InitDefine init;
init.PWM_Mode = CCMRn_PWM_MODE2; //模式, CCMRn_FREEZE,CCMRn_MATCH_VALID,CCMRn_MATCH_INVALID,CCMRn_ROLLOVER,CCMRn_FORCE_INVALID,CCMRn_FORCE_VALID,CCMRn_PWM_MODE1,CCMRn_PWM_MODE2
init.PWM_Period = PERIOD -1; //周期时间, 0~65535
init.PWM_Duty = 0; //占空比时间, 0~Period
init.PWM_DeadTime = 0 ; //死区发生器设置, 0~255
init.PWM_EnoSelect = ENO1P|ENO1N|ENO2P|ENO2N|ENO3P|ENO3N|ENO4P|ENO4N; //输出通道选择, ENO1P,ENO1N,ENO2P,ENO2N,ENO3P,ENO3N,ENO4P,ENO4N / ENO5P,ENO6P,ENO7P,ENO8P
init.PWM_CEN_Enable = ENABLE; //使能计数器, ENABLE,DISABLE
init.PWM_MainOutEnable = ENABLE;//主输出使能, ENABLE,DISABLE
PWM_Configuration(PWM1 , &init);
PWM_Configuration(PWM2 , &init);
PWM_Configuration(PWM3 , &init);
PWM_Configuration(PWM4 , &init);
PWM_Configuration(PWMA , &init);
//中断使能
NVIC_PWM_Init(PWMA , DISABLE , Priority_1);
//切换引脚
PWM1_SW(PWM1_SW_P20_P21) ;
PWM2_SW(PWM2_SW_P22_P23) ;
PWM3_SW(PWM3_SW_P14_P15) ;
PWM4_SW(PWM4_SW_P26_P27) ;
}
void UART_config(void) {
// >>> 记得添加 NVIC.c, UART.c, UART_Isr.c <<<
COMx_InitDefine COMx_InitStructure; //结构定义
COMx_InitStructure.UART_Mode = UART_8bit_BRTx; //模式, UART_ShiftRight,UART_8bit_BRTx,UART_9bit,UART_9bit_BRTx
COMx_InitStructure.UART_BRT_Use = BRT_Timer1; //选择波特率发生器, BRT_Timer1, BRT_Timer2 (注意: 串口2固定使用BRT_Timer2)
COMx_InitStructure.UART_BaudRate = 115200ul; //波特率, 一般 110 ~ 115200
COMx_InitStructure.UART_RxEnable = ENABLE; //接收允许, ENABLE或DISABLE
COMx_InitStructure.BaudRateDouble = DISABLE; //波特率加倍, ENABLE或DISABLE
UART_Configuration(UART1, &COMx_InitStructure); //初始化串口1 UART1,UART2,UART3,UART4
NVIC_UART1_Init(ENABLE,Priority_1); //中断使能, ENABLE/DISABLE; 优先级(低到高) Priority_0,Priority_1,Priority_2,Priority_3
UART1_SW(UART1_SW_P30_P31); // 引脚选择, UART1_SW_P30_P31,UART1_SW_P36_P37,UART1_SW_P16_P17,UART1_SW_P43_P44
}
PWMx_Duty duty;
void main(){
//定义一个比例值: 0 ~ 100;
int percent = 0 ;
int direction = 1;
//打开外部扩展寄存器使能:: PWM 一定要打开这个开关
EAXSFR();
//0. 中断总开关
EA = 1 ;
//1. 配置IO
GPIO_Config();
//2. 配置PWM
PWM_Config();
//3. 配置串口
UART_config();
//3. 打开LED的总开关
LED_SW = 0;
//4.点亮八个LED灯
LED1 = LED2 = LED3 = LED4 = LED5 = LED6 = LED7 = LED8 = 0;
while(1){
if(COM1.RX_TimeOut >0 && --COM1.RX_TimeOut == 0 ){
if(COM1.RX_Cnt > 0 ){
if(RX1_Buffer[0] == 0x01){ // 上升的过程 +1
direction = 1;
}else { // 下降的过程 -1
direction = -1;
}
percent += direction;
if(percent >= 100){
percent = 100;
}else if(percent <= 0){
percent = 0 ;
}
duty.PWM1_Duty =PERIOD * percent / 100;
duty.PWM2_Duty =PERIOD * percent / 100;
duty.PWM3_Duty =PERIOD * percent / 100;
duty.PWM4_Duty =PERIOD * percent / 100;
UpdatePwm(PWMA, &duty);
}
COM1.RX_Cnt = 0 ;
}
delay_ms(20);
}
}
震动马达
原理图
这里用到的三极管是NPN型三极管,基极电压为0也就是默认状态下三极管是断开的,要想要马达震动就要通过P0.1引脚给三极管一个高电压从而实现电机震动。
马达震动代码
#include "GPIO.h"
#include "Delay.h"
void GPIO_config(void) {
GPIO_InitTypeDef GPIO_InitStructure; //结构定义
GPIO_InitStructure.Pin = GPIO_Pin_1; //指定要初始化的IO,
GPIO_InitStructure.Mode = GPIO_OUT_PP; //指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP
GPIO_Inilize(GPIO_P0, &GPIO_InitStructure);//初始化
}
void main(){
//1. 初始化IO口
GPIO_config();
while(1){
//启动
P01 = 1;
delay_ms(250);
delay_ms(250);
delay_ms(250);
delay_ms(250);
//停止
P01 = 0;
delay_ms(250);
delay_ms(250);
delay_ms(250);
delay_ms(250);
}
}
PWM控制马达
代码如下:
#include "GPIO.h"
#include "NVIC.h"
#include "Switch.h"
#include "STC8H_PWM.h"
#include "delay.h"
void GPIO_Config(){
//1. P01
GPIO_InitTypeDef GPIO_InitStructure; //结构定义
GPIO_InitStructure.Pin = GPIO_Pin_1; //指定要初始化的IO,
GPIO_InitStructure.Mode = GPIO_OUT_PP; //指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP
GPIO_Inilize(GPIO_P0, &GPIO_InitStructure);//初始化
}
#define PERIOD MAIN_Fosc/1000
void PWM_Config(){
PWMx_InitDefine init;
init.PWM_Mode = CCMRn_PWM_MODE2; //模式, CCMRn_FREEZE,CCMRn_MATCH_VALID,CCMRn_MATCH_INVALID,CCMRn_ROLLOVER,CCMRn_FORCE_INVALID,CCMRn_FORCE_VALID,CCMRn_PWM_MODE1,CCMRn_PWM_MODE2
init.PWM_Period = PERIOD -1; //周期时间, 0~65535
init.PWM_Duty = 0; //占空比时间, 0~Period
init.PWM_DeadTime = 0; //死区发生器设置, 0~255
init.PWM_EnoSelect = ENO6P; //输出通道选择, ENO1P,ENO1N,ENO2P,ENO2N,ENO3P,ENO3N,ENO4P,ENO4N / ENO5P,ENO6P,ENO7P,ENO8P
init.PWM_CEN_Enable = ENABLE; //使能计数器, ENABLE,DISABLE
init.PWM_MainOutEnable = ENABLE;//主输出使能, ENABLE,DISABLE
PWM_Configuration(PWM6 , &init);
PWM_Configuration(PWMB , &init);
//NVIC_PWM_Init
// 切换引脚
PWM6_SW(PWM6_SW_P01);
}
PWMx_Duty duty;
void main(){
//定义一个比例值: 0 ~ 100;
int percent = 0 ;
int direction = 1;
//打开外部扩展寄存器使能:: PWM 一定要打开这个开关
EAXSFR();
//0. 中断总开关
EA = 1 ;
//1. 配置IO
GPIO_Config();
//2. 配置PWM
PWM_Config();
while(1){
//设置比例值
percent += direction;
//判断峰值,然后改变方向
if(percent >= 100){
direction = -1;
}else if(percent <= 0){
direction = 1;
}
//更新占空比
duty.PWM6_Duty = PERIOD * percent / 100;
UpdatePwm(PWM6 , &duty);
delay_ms(10);
}
}
电位器案例(ADC)
案例介绍
我们通过实验对比代码读取P5.0位置的电压和用万用表读取P5.0位置的电压。
ADC介绍
ADC(Analog to Digital Converter 模数转换器)是一种将模拟信号转换为数字信号的电路。在电子系统中,模拟信号常常需要转换为数字信号进行处理和存储。模数转换的基本原理是将模拟信号进行采样,并将采样值量化为数字表示。
- 采样:是指在一定时间间隔内对模拟信号进行测量,并将测量值存储在数字形式的数据中
- 量化:是将这些连续的模拟信号值离散化为一系列数字值,通常使用二进制表示。
简单理解,ADC是把模拟信号转换为数字信号的工具,我们可以认为,一个信号有强弱之分,强弱的体现为电压的高低。在数字电路中,只有0和1之分,也就是高电平或低电平。那么体现不了这个强弱。ADC的作用就是体现强弱,精确化的拿到具体的值。
应用场景:
- 医疗设备:如心电图、血压计之类。
- 音频信号处理:在数字音频处理中,ADC将模拟音频信号转换为数字信号,然后可以进行数字信号处理和存储。
- 电力系统:测量电压。
总之,需要知道信号强弱的,需要将模拟信号转为数字信号的都会用到ADC。
STC8H芯片有15个通道的ADC功能引脚:
ADC功能 | 引脚 |
ADC0 | P1.0 |
ADC1 | P1.1 |
ADC2 | P5.4 |
ADC3 | P1.3 |
ADC4 | P1.4 |
ADC5 | P1.5 |
ADC6 | P1.6 |
ADC7 | P1.7 |
ADC8 | P0.0 |
ADC9 | P0.1 |
ADC10 | P0.2 |
ADC11 | P0.3 |
ADC12 | P0.4 |
ADC13 | P0.5 |
ADC14 | P0.6 |
代码展示
#include "GPIO.h"
#include "NVIC.h"
#include "Switch.h"
#include "Delay.h"
#include "UART.h"
#include "ADC.h"
void GPIO_config(void) {
GPIO_InitTypeDef GPIO_InitStructure; //结构定义
GPIO_InitStructure.Pin = GPIO_Pin_5; //指定要初始化的IO,
GPIO_InitStructure.Mode = GPIO_HighZ; //指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP
GPIO_Inilize(GPIO_P0, &GPIO_InitStructure);//初始化
}
void UART_config(void) {
// >>> 记得添加 NVIC.c, UART.c, UART_Isr.c <<<
COMx_InitDefine COMx_InitStructure; //结构定义
COMx_InitStructure.UART_Mode = UART_8bit_BRTx; //模式, UART_ShiftRight,UART_8bit_BRTx,UART_9bit,UART_9bit_BRTx
COMx_InitStructure.UART_BRT_Use = BRT_Timer1; //选择波特率发生器, BRT_Timer1, BRT_Timer2 (注意: 串口2固定使用BRT_Timer2)
COMx_InitStructure.UART_BaudRate = 115200ul; //波特率, 一般 110 ~ 115200
COMx_InitStructure.UART_RxEnable = ENABLE; //接收允许, ENABLE或DISABLE
COMx_InitStructure.BaudRateDouble = DISABLE; //波特率加倍, ENABLE或DISABLE
UART_Configuration(UART1, &COMx_InitStructure); //初始化串口1 UART1,UART2,UART3,UART4
NVIC_UART1_Init(ENABLE,Priority_1); //中断使能, ENABLE/DISABLE; 优先级(低到高) Priority_0,Priority_1,Priority_2,Priority_3
UART1_SW(UART1_SW_P30_P31); // 引脚选择, UART1_SW_P30_P31,UART1_SW_P36_P37,UART1_SW_P16_P17,UART1_SW_P43_P44
}
//ADC的配置
void ADC_config(){
ADC_InitTypeDef init;
init.ADC_SMPduty = 31; //ADC 模拟信号采样时间控制, 0~31(注意: SMPDUTY 一定不能设置小于 10)
init.ADC_Speed = ADC_SPEED_2X1T; //设置 ADC 工作时钟频率 ADC_SPEED_2X1T~ADC_SPEED_2X16T
init.ADC_AdjResult = ADC_RIGHT_JUSTIFIED; //ADC结果 得到的测量值是2个字节来存储... 调整, ADC_LEFT_JUSTIFIED 【左对齐】,ADC_RIGHT_JUSTIFIED 【右对齐】
init.ADC_CsSetup = 0 ; //ADC 通道选择时间控制 0(默认),1
init.ADC_CsHold = 1; //ADC 通道选择保持时间控制 0,1(默认),2,3
//配置初始化
ADC_Inilize(&init);
//启动ADC
ADC_PowerControl(ENABLE);
//中断使能
//NVIC_ADC_init
//没有切换什么引脚...
}
void main(){
u16 result ;
float result_v ;
//中断开关
EA = 1;
//2/ IO模式
GPIO_config();
//3. 串口配置
UART_config();
//4. ADC配置
ADC_config();
printf("start..\n");
while(1){
// 目标:: 获取电压值
//1. 测到的ADC测量值
result = Get_ADCResult(ADC_CH13);
printf("result=%d \n" , result);
//2. 根据公式得到电压值
result_v = result * 2.5 / 4096;
printf("result_v=%.2f \n" , result_v);
delay_ms(250);
delay_ms(250);
delay_ms(250);
delay_ms(250);
}
}
基准电压
ADC为12位精度的,意思是最大值是2的12次方,值为4096.
ADC的这个最大值,表示的是最大测量范围:
- 数值最大为4096
- 测量的电压值不能超过基准电压
- 基准电压对应的值为4096
记住:我们用4096表示基准电压。
以上原理图中,基准电压由 VREF
电压决定。这个电路中用到了一个芯片CJ431/CD431
,这是一款电压基准芯片,会恒定的输出2.5V
电压。
在我们的设计方案中,理论上可以不使用这个电压基准芯片的,直接连接3V3,但是LDO的输出稳定性不够,因此使用电压基准芯片会更为准确。
由以上我们可以得出:
- 基准电压为:2.5V
- 基准电压对应的数值是4096
- 测量的值为ADC引脚
- 电压值的计算:电压值=测量值*基准电压 / 4096
热敏电阻
案例介绍
ADC功能引脚参照电位器部分
计算步骤
详解
第一步:通过上面计算的电压值计算电阻值:电阻=测量电压*10 / (3.3-测量电压)。阻值特性表部分如上,全部请查阅数据手册。
第二步:先拿出来数组的第0位和计算出来的电阻值进行比较,认为这个差值就是最小值,当做一个标准。
第三步:遍历每一个数组元素
第四步:让遍历出来的每一个元素和得到的电压值(*100),计算得到差值。这里为什么*100,是因为方便和阻温特性表进行比较。
第五步:判断最小差值,并且记录最小差值对应的索引。
第六步:拿着索引下表-55即可得到温度值了。这里我们也可以定义温度和中心支两个数组,然后取对应的索引得到温度值,但是有点麻烦,实际上我们拿对应的索引-55就直接能得到温度值了,请参考阻温特性表。
代码如下
#include "GPIO.h"
#include "NVIC.h"
#include "Switch.h"
#include "Delay.h"
#include "UART.h"
#include "ADC.h"
//准备好了阻值数组
u16 code temp_table[]= {
58354, // -55
55464, // -54
52698, // -53
50048, // -52
47515, // -51
45097, // -50
42789, // -49
40589, // -48
38492, // -47
36496, // -46
34597, // -45
32791, // -44
31075, // -43
29444, // -42
27896, // -41
26427, // -40
25034, // -39
23713, // -38
22460, // -37
21273, // -36
20148, // -35
19083, // -34
18075, // -33
17120, // -32
16216, // -31
15361, // -30
14551, // -29
13785, // -28
13061, // -27
12376, // -26
11728, // -25
11114, // -24
10535, // -23
9986, // -22
9468, // -21
8977, // -20
8513, // -19
8075, // -18
7660, // -17
7267, // -16
6896, // -15
6545, // -14
6212, // -13
5898, // -12
5601, // -11
5319, // -10
5053, // -9
4801, // -8
4562, // -7
4336, // -6
4122, // -5
3920, // -4
3728, // -3
3546, // -2
3374, // -1
3211, // 0
3057, // 1
2910, // 2
2771, // 3
2639, // 4
2515, // 5
2396, // 6
2284, // 7
2177, // 8
2076, // 9
1978, // 10
1889, // 11
1802, // 12
1720, // 13
1642, // 14
1568, // 15
1497, // 16
1430, // 17
1366, // 18
1306, // 19
1248, // 20
1193, // 21
1141, // 22
1092, // 23
1044, // 24
1000, // 25
957, // 26
916, // 27
877, // 28
840, // 29
805, // 30
771, // 31
739, // 32
709, // 33
679, // 34
652, // 35
625, // 36
600, // 37
576, // 38
552, // 39
530, // 40
509, // 41
489, // 42
470, // 43
452, // 44
434, // 45
417, // 46
401, // 47
386, // 48
371, // 49
358, // 50
344, // 51
331, // 52
318, // 53
306, // 54
295, // 55
284, // 56
274, // 57
264, // 58
254, // 59
245, // 60
236, // 61
228, // 62
220, // 63
212, // 64
205, // 65
198, // 66
191, // 67
184, // 68
178, // 69
172, // 70
166, // 71
160, // 72
155, // 73
150, // 74
145, // 75
140, // 76
135, // 77
131, // 78
126, // 79
122, // 80
118, // 81
115, // 82
111, // 83
107, // 84
104, // 85
101, // 86
97, // 87
94, // 88
91, // 89
89, // 90
86, // 91
83, // 92
81, // 93
78, // 94
76, // 95
74, // 96
71, // 97
69, // 98
67, // 99
65, // 100
63, // 101
61, // 102
60, // 103
58, // 104
56, // 105
55, // 106
53, // 107
52, // 108
50, // 109
49, // 110
47, // 111
46, // 112
45, // 113
43, // 114
42, // 115
41, // 116
40, // 117
39, // 118
38, // 119
37, // 120
36, // 121
35, // 122
34, // 123
33, // 124
32, // 125
};
void GPIO_config(void) {
GPIO_InitTypeDef GPIO_InitStructure; //结构定义
GPIO_InitStructure.Pin = GPIO_Pin_4; //指定要初始化的IO,
GPIO_InitStructure.Mode = GPIO_HighZ; //指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP
GPIO_Inilize(GPIO_P0, &GPIO_InitStructure);//初始化
}
void UART_config(void) {
// >>> 记得添加 NVIC.c, UART.c, UART_Isr.c <<<
COMx_InitDefine COMx_InitStructure; //结构定义
COMx_InitStructure.UART_Mode = UART_8bit_BRTx; //模式, UART_ShiftRight,UART_8bit_BRTx,UART_9bit,UART_9bit_BRTx
COMx_InitStructure.UART_BRT_Use = BRT_Timer1; //选择波特率发生器, BRT_Timer1, BRT_Timer2 (注意: 串口2固定使用BRT_Timer2)
COMx_InitStructure.UART_BaudRate = 115200ul; //波特率, 一般 110 ~ 115200
COMx_InitStructure.UART_RxEnable = ENABLE; //接收允许, ENABLE或DISABLE
COMx_InitStructure.BaudRateDouble = DISABLE; //波特率加倍, ENABLE或DISABLE
UART_Configuration(UART1, &COMx_InitStructure); //初始化串口1 UART1,UART2,UART3,UART4
NVIC_UART1_Init(ENABLE,Priority_1); //中断使能, ENABLE/DISABLE; 优先级(低到高) Priority_0,Priority_1,Priority_2,Priority_3
UART1_SW(UART1_SW_P30_P31); // 引脚选择, UART1_SW_P30_P31,UART1_SW_P36_P37,UART1_SW_P16_P17,UART1_SW_P43_P44
}
//ADC的配置
void ADC_config(){
ADC_InitTypeDef init;
init.ADC_SMPduty = 31; //ADC 模拟信号采样时间控制, 0~31(注意: SMPDUTY 一定不能设置小于 10)
init.ADC_Speed = ADC_SPEED_2X1T; //设置 ADC 工作时钟频率 ADC_SPEED_2X1T~ADC_SPEED_2X16T
init.ADC_AdjResult = ADC_RIGHT_JUSTIFIED; //ADC结果调整, ADC_LEFT_JUSTIFIED,ADC_RIGHT_JUSTIFIED
init.ADC_CsSetup = 0; //ADC 通道选择时间控制 0(默认),1
init.ADC_CsHold = 1; //ADC 通道选择保持时间控制 0,1(默认),2,3
ADC_Inilize(&init);
ADC_PowerControl(ENABLE);
}
#define abs(x) (x)>0 ? (x) : (-(x))
void main(){
int i , temprature , index = 0;
u16 result ;
float result_v , result_r , min , diff;
//中断开关
EA = 1;
//2/ IO模式
GPIO_config();
//3. 串口配置
UART_config();
//4. ADC配置
ADC_config();
printf("start..\n");
while(1){
//1. 获取到ADC的测量值
result = Get_ADCResult(ADC_CH12);
//2. 根据测量值计算出来电压值
result_v = result * 2.5 / 4096;
//3. 根据电压值,计算电阻值:: 电阻 = 测量电压 * 10 / (3.3 - 测量电压)
result_r = result_v * 10 / (3.3 - result_v );
printf("电阻: %.2f\n" , result_r);
//4. 根据电阻值,计算出来温度值
result_r *= 100;
//4.0 先拿数组的第0位出来和现在得到的电阻值进行差值比较【然后就认为现在这个差值就是最小的差值!】
//min = (result_r - temp_table[0]) > 0 ? (result_r - temp_table[0]) : (-(result_r - temp_table[0]));
min = abs(result_r - temp_table[0]);
//4.1 遍历数组的每一个元素
for(i = 1 ; i < sizeof(temp_table) / sizeof(u16) ; i++){
//4.2 让数组的每一个元素和得到的 (电压值 * 100) 计算得到差值
//diff = (result_r - temp_table[i]) > 0 ? (result_r - temp_table[i]) : (-(result_r - temp_table[i] ));
diff = abs(result_r - temp_table[i]);
//4.3 判断最小差值
if(min > diff){
min = diff;
//4.3 差值最小的,要记录它的索引下标 【就是我们要找到的温度】
index = i ;
}
}
//4.4 拿着索引下标 - 55 即可得到温度值了。
temprature = index - 55;
printf("现在的温度值是:%d\n" , temprature);
delay_ms(250);
delay_ms(250);
delay_ms(250);
delay_ms(250);
}
}
总结
今天主要介绍了PWM,其实学习起来并不难,明白了PWM配置的基本方法,包括更新占空比等操作PWM也就算了入门了。我们下期再见!