本文主要是介绍STC8增强型单片机开发day04,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
热敏电阻
NTC(Negative Temperature Coefficient)是指随温度上升电阻减小、具有负温度系数的热敏电阻现象和材料
原理图
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 |
温度计算步骤
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.3V−Vntc=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.3V−VntcVntc⋅R10k
3. 通过阻值查表得到温度
采用表的方式来记录 电阻值和温度的关系。
其中,表中记录的是阻值,下标记录的是温度。可以通过阻值比对,查询出下标,下标就是对应的温度。
u16 code temp_table[]= {58354, // -5555464, // -5452698, // -5350048, // -5247515, // -5145097, // -5042789, // -4940589, // -4838492, // -4736496, // -4634597, // -4532791, // -4431075, // -4329444, // -4227896, // -4126427, // -4025034, // -3923713, // -3822460, // -3721273, // -3620148, // -3519083, // -3418075, // -3317120, // -3216216, // -3115361, // -3014551, // -2913785, // -2813061, // -2712376, // -2611728, // -2511114, // -2410535, // -239986, // -229468, // -218977, // -208513, // -198075, // -187660, // -177267, // -166896, // -156545, // -146212, // -135898, // -125601, // -115319, // -105053, // -94801, // -84562, // -74336, // -64122, // -53920, // -43728, // -33546, // -23374, // -13211, // 03057, // 12910, // 22771, // 32639, // 42515, // 52396, // 62284, // 72177, // 82076, // 91978, // 101889, // 111802, // 121720, // 131642, // 141568, // 151497, // 161430, // 171366, // 181306, // 191248, // 201193, // 211141, // 221092, // 231044, // 241000, // 25957, // 26916, // 27877, // 28840, // 29805, // 30771, // 31739, // 32709, // 33679, // 34652, // 35625, // 36600, // 37576, // 38552, // 39530, // 40509, // 41489, // 42470, // 43452, // 44434, // 45417, // 46401, // 47386, // 48371, // 49358, // 50344, // 51331, // 52318, // 53306, // 54295, // 55284, // 56274, // 57264, // 58254, // 59245, // 60236, // 61228, // 62220, // 63212, // 64205, // 65198, // 66191, // 67184, // 68178, // 69172, // 70166, // 71160, // 72155, // 73150, // 74145, // 75140, // 76135, // 77131, // 78126, // 79122, // 80118, // 81115, // 82111, // 83107, // 84104, // 85101, // 8697, // 8794, // 8891, // 8989, // 9086, // 9183, // 9281, // 9378, // 9476, // 9574, // 9671, // 9769, // 9867, // 9965, // 10063, // 10161, // 10260, // 10358, // 10456, // 10555, // 10653, // 10752, // 10850, // 10949, // 11047, // 11146, // 11245, // 11343, // 11442, // 11541, // 11640, // 11739, // 11838, // 11937, // 12036, // 12135, // 12234, // 12333, // 12432, // 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_PPGPIO_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(默认),1ADC_InitStructure.ADC_CsHold = 1; //ADC 通道选择保持时间控制 0,1(默认),2,3ADC_InitStructure.ADC_Speed = ADC_SPEED_2X1T; //设置 ADC 工作时钟频率 ADC_SPEED_2X1T~ADC_SPEED_2X16TADC_InitStructure.ADC_AdjResult = ADC_RIGHT_JUSTIFIED; //ADC结果调整, ADC_LEFT_JUSTIFIED,ADC_RIGHT_JUSTIFIEDADC_Inilize(&ADC_InitStructure); //初始化ADC_PowerControl(ENABLE); //ADC电源开关, ENABLE或DISABLENVIC_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]);// 得到差值最小元素对应的索引iif(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);
独立按键
原理图
按键消抖
-
软件延时法:在按键按下时,使用软件延时一段时间,例如10毫秒,然后再检测按键是否还处于按下状态,如果是,则认为按键有效。这种方法简单易行,但会浪费一定的处理器时间,同时需要根据实际情况调整延时时间。
-
硬件滤波法:在按键输入引脚上添加RC滤波电路,可以有效地去除按键信号上的瞬间噪声。这种方法对于高频噪声的去除效果较好,但需要一定的电路设计能力。
-
程序消抖法:在程序中记录按键前后两次的状态,如果两次状态不同,则认为按键有效。这种方法可以根据需要调整检测时间,消抖效果较好,但需要额外的程序设计。
我们采用程序消抖法。
软件设计
要求
当用户按下,或者松开按键时,捕获到这个事件。将事件通过串口发出来。
分析
监控引脚的高低电平变化。记录状态,比对实时状态。
● 监控:死循环去读取电平信息
● 记录与比对:通过变量记录,实时拿到当前状态,与记录的上一次进行比对。
实现单个按钮
#include "Config.h"
#include "Delay.h"
#include "GPIO.h"
#include "UART.h"
#include "NVIC.h"
#include "Switch.h"#define KEY1 P51void 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_BRTxCOMx_InitStructure.UART_BRT_Use = BRT_Timer1; //选择波特率发生器, BRT_Timer1, BRT_Timer2 (注意: 串口2固定使用BRT_Timer2)COMx_InitStructure.UART_BaudRate = 115200ul; //波特率, 一般 110 ~ 115200COMx_InitStructure.UART_RxEnable = ENABLE; //接收允许, ENABLE或DISABLECOMx_InitStructure.BaudRateDouble = DISABLE; //波特率加倍, ENABLE或DISABLEUART_Configuration(UART1, &COMx_InitStructure); //初始化串口1 UART1,UART2,UART3,UART4NVIC_UART1_Init(ENABLE,Priority_1); //中断使能, ENABLE/DISABLE; 优先级(低到高) Priority_0,Priority_1,Priority_2,Priority_3UART1_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 0printf("KEY1 up\n");last_key_state = 1;}else if(KEY1 == 0 && last_key_state == 1){// 当前是按下Down 0, 上一次是抬起Up 1printf("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 P54void 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_BRTxCOMx_InitStructure.UART_BRT_Use = BRT_Timer1; //选择波特率发生器, BRT_Timer1, BRT_Timer2 (注意: 串口2固定使用BRT_Timer2)COMx_InitStructure.UART_BaudRate = 115200ul; //波特率, 一般 110 ~ 115200COMx_InitStructure.UART_RxEnable = ENABLE; //接收允许, ENABLE或DISABLECOMx_InitStructure.BaudRateDouble = DISABLE; //波特率加倍, ENABLE或DISABLEUART_Configuration(UART1, &COMx_InitStructure); //初始化串口1 UART1,UART2,UART3,UART4NVIC_UART1_Init(ENABLE,Priority_1); //中断使能, ENABLE/DISABLE; 优先级(低到高) Priority_0,Priority_1,Priority_2,Priority_3UART1_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 1u8 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] = UPvoid main(){GPIO_config();UART_config();EA = 1;while(1){if(KEY1 && IS_KEY_DOWN(0)){ // 这次是抬起Up 1, 上一次是按下Down 0printf("KEY1 up\n");SET_KEY_UP(0);}else if(!KEY1 && IS_KEY_UP(0)){// 这次是按下Down 0, 上一次是抬起Up 1printf("KEY1 down\n"); SET_KEY_DOWN(0);}if(KEY2 && IS_KEY_DOWN(1)){ // 这次是抬起Up 1, 上一次是按下Down 0printf("KEY2 up\n");SET_KEY_UP(1);}else if(!KEY2 && IS_KEY_UP(1)){// 这次是按下Down 0, 上一次是抬起Up 1printf("KEY2 down\n"); SET_KEY_DOWN(1);}if(KEY3 && IS_KEY_DOWN(2)){ // 这次是抬起Up 1, 上一次是按下Down 0printf("KEY3 up\n");SET_KEY_UP(2);}else if(!KEY3 && IS_KEY_UP(2)){// 这次是按下Down 0, 上一次是抬起Up 1printf("KEY3 down\n"); SET_KEY_DOWN(2);}if(KEY4 && IS_KEY_DOWN(3)){ // 这次是抬起Up 1, 上一次是按下Down 0printf("KEY4 up\n");SET_KEY_UP(3);}else if(!KEY4 && IS_KEY_UP(3)){// 这次是按下Down 0, 上一次是抬起Up 1printf("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位
这篇关于STC8增强型单片机开发day04的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!