STC进阶开发(一)PWM、ADC、热敏电阻

前言

        上一期后面我们简单的介绍了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的作用就是体现强弱,精确化的拿到具体的值。

应用场景:

  1. 医疗设备:如心电图、血压计之类。
  2. 音频信号处理:在数字音频处理中,ADC将模拟音频信号转换为数字信号,然后可以进行数字信号处理和存储。
  3. 电力系统:测量电压。

总之,需要知道信号强弱的,需要将模拟信号转为数字信号的都会用到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的这个最大值,表示的是最大测量范围:

  1. 数值最大为4096
  2. 测量的电压值不能超过基准电压
  3. 基准电压对应的值为4096

记住:我们用4096表示基准电压。

以上原理图中,基准电压由 VREF电压决定。这个电路中用到了一个芯片CJ431/CD431,这是一款电压基准芯片,会恒定的输出2.5V电压。

在我们的设计方案中,理论上可以不使用这个电压基准芯片的,直接连接3V3,但是LDO的输出稳定性不够,因此使用电压基准芯片会更为准确。

由以上我们可以得出:

  1. 基准电压为:2.5V
  2. 基准电压对应的数值是4096
  3. 测量的值为ADC引脚
  4. 电压值的计算:电压值=测量值*基准电压 / 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也就算了入门了。我们下期再见!

  • 32
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

'Magic'

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值