STC8增强型单片机开发day04

热敏电阻

NTC(Negative Temperature Coefficient)是指随温度上升电阻减小、具有负温度系数的热敏电阻现象和材料

原理图

在这里插入图片描述

ADC功能引脚
ADC0P1.0
ADC1P1.1
ADC2P5.4
ADC3P1.3
ADC4P1.4
ADC5P1.5
ADC6P1.6
ADC7P1.7
ADC8P0.0
ADC9P0.1
ADC10P0.2
ADC11P0.3
ADC12P0.4
ADC13P0.5
ADC14P0.6

温度计算步骤

1. 通过ADC采样计算出热敏电阻位置的电压

V n t c 2.5 = A D C _ V a l u e 4096 V n t c = 2.5 × A D C _ V a l u e 4096 \begin{aligned} \frac{V_{ntc}}{2.5} &= \frac{ADC\_Value}{4096} \\ \\ V_{ntc} &= 2.5 \times \frac{ADC\_Value}{4096} \end{aligned} 2.5VntcVntc=4096ADC_Value=2.5×4096ADC_Value

○ ADC_Value就是通过ADC采样出来的的数值,范围是0-4096。
○ V_ntc即为对应的电压值

2. 通过欧姆定律计算热敏电阻的阻值

V n t c R n t c = 3.3 V − V n t c R 10 K = 3.3 V R 10 K + R n t c \frac{V_{ntc}}{R_{ntc}} = \frac{3.3V-V_{ntc}}{R_{10K}} = \frac{3.3V}{R_{10K} + R_{ntc}} RntcVntc=R10K3.3VVntc=R10K+Rntc3.3V

串联分压,电流不变。上面是热敏电阻ntc和10k电阻的电流等式,根据公式推导出热敏电阻的阻值计算公式:
R n t c = V n t c ⋅ R 10 k 3.3 V − V n t c R_{ntc} = \frac{V_{ntc} \cdot R_{10k}}{3.3V-V_{ntc}} Rntc=3.3VVntcVntcR10k

3. 通过阻值查表得到温度

在这里插入图片描述
采用表的方式来记录 电阻值和温度的关系。
其中,表中记录的是阻值,下标记录的是温度。可以通过阻值比对,查询出下标,下标就是对应的温度。

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
};

代码参考

创建NTC.h,写入如下内容

#ifndef __NTC_H__
#define __NTC_H__

#include "Config.h"

// 求绝对值
#define abs(x)	((x > 0) ? (x) : (-(x)))

#define NTC_GPIO			GPIO_P0

#define NTC_GPIO_PIN	GPIO_Pin_4

#define NTC_ACD_CH		ADC_CH12

// 初始化NTC
void NTC_init();

// 获取温度值
int NTC_get_temperature();

#endif

创建一个NTC.c文件,写入如下内容,请自行将temp_table拷贝进来

#include "NTC.h"
#include "GPIO.h"
#include "ADC.h"
#include "NVIC.h"
#include <stdio.h>

static void GPIO_config(void) {
    GPIO_InitTypeDef	GPIO_InitStructure;		//结构定义
    GPIO_InitStructure.Pin  = NTC_GPIO_PIN;		//指定要初始化的IO,
    GPIO_InitStructure.Mode = GPIO_HighZ;	//指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP
    GPIO_Inilize(NTC_GPIO, &GPIO_InitStructure);//初始化
}

/******************* AD配置函数 *******************/
void	ADC_config(void)
{
	ADC_InitTypeDef		ADC_InitStructure;		//结构定义

	ADC_InitStructure.ADC_SMPduty   = 31;		//ADC 模拟信号采样时间控制, 0~31(注意: SMPDUTY 一定不能设置小于 10)
	ADC_InitStructure.ADC_CsSetup   = 0;		//ADC 通道选择时间控制 0(默认),1
	ADC_InitStructure.ADC_CsHold    = 1;		//ADC 通道选择保持时间控制 0,1(默认),2,3
	ADC_InitStructure.ADC_Speed     = ADC_SPEED_2X1T;		//设置 ADC 工作时钟频率	ADC_SPEED_2X1T~ADC_SPEED_2X16T
	ADC_InitStructure.ADC_AdjResult = ADC_RIGHT_JUSTIFIED;	//ADC结果调整,	ADC_LEFT_JUSTIFIED,ADC_RIGHT_JUSTIFIED
	ADC_Inilize(&ADC_InitStructure);		//初始化
	ADC_PowerControl(ENABLE);				//ADC电源开关, ENABLE或DISABLE
	NVIC_ADC_Init(DISABLE,Priority_0);		//中断使能, ENABLE/DISABLE; 优先级(低到高) Priority_0,Priority_1,Priority_2,Priority_3
}

// 初始化NTC
void NTC_init() {
    GPIO_config();
    ADC_config();
}

static int search_temp(float rst_Rx10){
	int i, min_index = 0;

	// 计算数组长度
	int len = sizeof(temp_table) / sizeof(u16);
	
	// 记录最小差值 
	float min_diff = abs(rst_Rx10 - temp_table[0]);
	
	for (i = 1; i < len; i++){
		// 计算数组里每一个阻值和rst_Rx10的差值
		float diff = abs(rst_Rx10 - temp_table[i]);
		
		// 得到差值最小元素对应的索引i
		if(diff < min_diff){
			// 如果有更小的差值,赋值
			min_diff = diff;
			min_index = i;
		}
	}
	
	printf("len: %d R: %.2f min_diff: %.2f min_index: %d \n", len, rst_Rx10, min_diff, min_index);
	
	return min_index;
}

// 获取温度值
int NTC_get_temperature() {
    u16 adc_value;
    float rst_V;
    float rst_R;
    int rst_T;

    // 获取对应的ADC值
    adc_value = Get_ADCResult(NTC_ACD_CH);

    // adc_value返回的值范围 0 -> 4096
    // 等同于P05引脚的电压值和Vref的占比  1024
    // X = ADC_V  * Vref / 4096
    // 计算电压
    rst_V = adc_value * 2.5 / 4096;

    // 计算电阻值
    rst_R = rst_V * 10 / (3.3 - rst_V);

    // 9.36KΩ 将阻值兑换成温度
    rst_T = search_temp(rst_R * 100) - 55;

    printf("ADC: %d voltage: %.2f R = %.2f T = %d℃ \n", adc_value, rst_V, rst_R, (int)rst_T);
		
		return rst_T;
}

main函数中:


int rst_T;
NTC_init();

rst_T = NTC_get_temperature();
printf("温度:%d \n", rst_T);

独立按键

原理图

在这里插入图片描述

按键消抖

  1. 软件延时法:在按键按下时,使用软件延时一段时间,例如10毫秒,然后再检测按键是否还处于按下状态,如果是,则认为按键有效。这种方法简单易行,但会浪费一定的处理器时间,同时需要根据实际情况调整延时时间。

  2. 硬件滤波法:在按键输入引脚上添加RC滤波电路,可以有效地去除按键信号上的瞬间噪声。这种方法对于高频噪声的去除效果较好,但需要一定的电路设计能力。

  3. 程序消抖法:在程序中记录按键前后两次的状态,如果两次状态不同,则认为按键有效。这种方法可以根据需要调整检测时间,消抖效果较好,但需要额外的程序设计。

我们采用程序消抖法。

软件设计

要求

当用户按下,或者松开按键时,捕获到这个事件。将事件通过串口发出来。

分析

监控引脚的高低电平变化。记录状态,比对实时状态。
● 监控:死循环去读取电平信息
● 记录与比对:通过变量记录,实时拿到当前状态,与记录的上一次进行比对。

实现单个按钮
#include "Config.h"
#include "Delay.h"
#include "GPIO.h"
#include "UART.h"
#include "NVIC.h"
#include "Switch.h"

#define KEY1 P51

void GPIO_config(void) {
	P5_MODE_IO_PU(GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4);
}

void UART_config(void) {
    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
}

u8 last_key_state = 1; // 抬起

void main(){
	
	GPIO_config();
	UART_config();
	
	EA = 1;
	
	while(1){
		if(KEY1 == 1 && last_key_state == 0){ // 当前是抬起Up 1, 上一次是按下Down 0
			printf("KEY1 up\n");
			last_key_state = 1;
		}else if(KEY1 == 0 && last_key_state == 1){// 当前是按下Down 0, 上一次是抬起Up 1
			printf("KEY1 down\n");	
			last_key_state = 0;
		}
		delay_ms(20);
	}
}
实现多个按钮
#include "Config.h"
#include "Delay.h"
#include "GPIO.h"
#include "UART.h"
#include "NVIC.h"
#include "Switch.h"

#define KEY1 P51
#define KEY2 P52
#define KEY3 P53
#define KEY4 P54

void GPIO_config(void) {
	P5_MODE_IO_PU(GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4);
}


void UART_config(void) {
    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
}


#define	DOWN	0
#define	UP		1

u8 last_key_states[] = {UP, UP, UP, UP};		// key的最后一次状态

// 判断指定位置【是否是】按下或抬起
#define	IS_KEY_DOWN(i)		last_key_states[i] == DOWN
#define	IS_KEY_UP(i)		last_key_states[i] == UP

// 将指定位置值【设置】为按下或抬起
#define SET_KEY_DOWN(i)		last_key_states[i] = DOWN
#define SET_KEY_UP(i)		last_key_states[i] = UP

void main(){
	
	GPIO_config();
	UART_config();
	
	EA = 1;
	
	while(1){
		if(KEY1 && IS_KEY_DOWN(0)){ // 这次是抬起Up 1, 上一次是按下Down 0
			printf("KEY1 up\n");
			SET_KEY_UP(0);
		}else if(!KEY1 && IS_KEY_UP(0)){// 这次是按下Down 0, 上一次是抬起Up 1
			printf("KEY1 down\n");	
			SET_KEY_DOWN(0);
		}
		
		if(KEY2 && IS_KEY_DOWN(1)){ // 这次是抬起Up 1, 上一次是按下Down 0
			printf("KEY2 up\n");
			SET_KEY_UP(1);
		}else if(!KEY2 && IS_KEY_UP(1)){// 这次是按下Down 0, 上一次是抬起Up 1
			printf("KEY2 down\n");	
			SET_KEY_DOWN(1);
		}
		
		if(KEY3 && IS_KEY_DOWN(2)){ // 这次是抬起Up 1, 上一次是按下Down 0
			printf("KEY3 up\n");
			SET_KEY_UP(2);
		}else if(!KEY3 && IS_KEY_UP(2)){// 这次是按下Down 0, 上一次是抬起Up 1
			printf("KEY3 down\n");	
			SET_KEY_DOWN(2);
		}
		
		if(KEY4 && IS_KEY_DOWN(3)){ // 这次是抬起Up 1, 上一次是按下Down 0
			printf("KEY4 up\n");
			SET_KEY_UP(3);
		}else if(!KEY4 && IS_KEY_UP(3)){// 这次是按下Down 0, 上一次是抬起Up 1
			printf("KEY4 down\n");	
			SET_KEY_DOWN(3);
		}
		
		delay_ms(20);
	}
}
使用位操作存储状态
// P51, P52, P53, P54
//u8 last_key_states[] = {UP, UP, UP, UP}; 
// 0b 0 0 0 0 - 1 1 1 1
u8 last_key_states = 0x0F; 	// KEY最后一次状态的8个位(只使用低4位)

// 判断指定位置【是否】是按下
//  0b 0 0 0 0 - 0 0 0 0
//& 0b 0 0 0 0 - 0 1 0 0		----- 判断指定位i=2是否是0
//  0b 0 0 0 0 - 0 0 0 0			== 0
#define IS_KEY_DOWN(i)			(last_key_states & (1 << i)) == 0

// 判断指定位置【是否】是抬起
//  0b 0 0 0 0 - 1 1 0 0
//& 0b 0 0 0 0 - 1 0 0 0		----- 判断指定位i=3是否是1
//  0b 0 0 0 0 - 1 0 0 0			> 0
#define IS_KEY_UP(i)			(last_key_states & (1 << i)) > 0


// 将指定位置值【设置】为按下
//   0b 0 0 0 0 - 1 1 0 0			
//&= 0b 1 1 1 1 - 1 0 1 1		------ 将指定位i=2设置为0,按下
//&=~0b 0 0 0 0 - 0 1 0 0
//	 0b 0 0 0 0 - 1 0 0 0		
#define SET_KEY_DOWN(i)			last_key_states &= ~(1 << i)

// 将指定位置值【设置】为抬起
//   0b 0 0 0 0 - 1 1 0 0			
//|= 0b 0 0 0 0 - 0 0 1 0		------ 将指定位i=1设置为1,抬起
//   0b 0 0 0 0 - 1 1 1 0
#define SET_KEY_UP(i)			last_key_states |= (1 << i)

● u16存储状态: 16个 1 << i 只能存 16 位
● u32存储状态: 32个, 1 << i 要改成 1L << i 能存32位

  • 27
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

大鹅£

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

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

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

打赏作者

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

抵扣说明:

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

余额充值