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, // -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);

独立按键

原理图

在这里插入图片描述

按键消抖

  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 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位

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/697166.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

AI试衣IDM-VTON,Windows11本地安装配置记录!

昨天我们已经介绍过IDM-VTON这个开源项目了。 通过这个软件可以轻松实现一键换衣服。 昨天&#xff0c;简单演示了一下在线使用。 今天&#xff0c;来演示如何安装到本地电脑上&#xff01; 本地配置会有一定的专业性&#xff0c;懂的人可以参考下。 不懂得直接拉到最后&am…

智能酒精壁炉与酒店前台的氛围搭配

智能酒精壁炉与酒店前台的氛围搭配可以为前台区域增添舒适、现代和独特的氛围&#xff0c;以下是一些建议&#xff1a; 欢迎区域装饰&#xff1a; 将智能酒精壁炉作为前台欢迎区域的装饰物&#xff0c;放置在客人抵达的显眼位置。选择现代设计的壁炉款式&#xff0c;如壁挂式…

使用Eigen将经纬度、高程、偏北角转成变换矩阵

目录 1、前言 2、示例 3、代码解析 4、垂直于给定点的切平面变换 5、代码解析 1、前言 在地球表面进行刚体变换时候&#xff0c;要将具有经纬度、高程和偏北角的坐标信息转换为变换矩阵表达&#xff0c;首先需要了解坐标系之间的转换关系。 通常&#xff0c;我们会将经纬…

C# WinForm —— 18 NumericUpDown 介绍

1. 简介 数字显示框&#xff0c;通过向上、向下按钮来 增加/减小 显示的数值 2. 常用属性 属性解释(Name)控件ID&#xff0c;在代码里引用的时候会用到,一般以 numUD 开头Hexadecimal数值 up-down 控件的值是否应以十六进制显示Increment每单击一下按钮&#xff0c;增加或减…

LLVM中期报告

1&#xff0e;主要开展的工作 研究对LLVM IR层面进行代码混淆&#xff0c;分析IR的指令 &#xff0c;并且实现混淆 从LLVM代码混淆的角度出发&#xff0c;函数之间的正常调用构成了待混淆程序的原始控制流&#xff0c;不同的基础代码块构成了一个个的函数&#xff0c;每个基础…

【论文阅读】Machine Learning, Linear Algebra, and More: Is SQL All You Need?

文章目录 摘要一、介绍二、SQL算法原语2.1、Variables2.2、Functions2.3、Conditions2.4、Loops2.5、Errors 三、案例研究3.1、对数据库友好的SQL映射3.2、性能结果 四、结论以及未来工作 摘要 尽管SQL在简单的分析查询中无处不在&#xff0c;但它很少用于更复杂的计算&#xf…

泛微E9开发 添加多个多选框,实现单选框的效果

利用多个多选框实现单选框的效果 1、功能背景2、展示效果3、实现效果 1、功能背景 如下图所示&#xff0c;在表单中新增四个“选择框-复选框”类型的字段&#xff0c;并且设置其中的选项&#xff0c;每个多选框都只有一个选项&#xff0c;通过代码块实现单选框的效果 1.显示模…

idm下载到99.99%不动了 idm突然不下载了 idm下载到最后没速度咋办 IDM下载后没网了是怎么回事

idm能够帮助我们下载不同类型的网页视频&#xff0c;并且基于多线程下载技术的助力下使其下载速度比原来提升数倍以上&#xff0c;因此成为了许多朋友下载的小助手。但也有朋友反映idm下载网页视频超时连接不上&#xff0c;idm下载网页视频突然停止&#xff0c;究竟这些情况我们…

C++之Eigen库基本使用(下)

1、常见变换 Eigen::Matrix3d //旋转矩阵&#xff08;3*3&#xff09; Eigen::AngleAxisd //旋转向量&#xff08;3*1&#xff09; Eigen::Vector3d //欧拉角&#xff08;3*1&#xff09; Eigen::Quaterniond //四元数&#xff08;4*1&#xff09; Eigen::Isom…

[嵌入式系统-77]:RT-Thread-快速上手:嵌入式系统调测工具大全

目录 1. JTAG 下载调试器&#xff1a; 2. J-Link 仿真器&#xff1a; 3. ICE&#xff08;In-Circuit Emulator&#xff09;&#xff1a; 4. ROM监视器&#xff08;ROM Monitor&#xff09;&#xff1a; 5. 终端仿真工具&#xff1a; 6. 总线抓取工具&#xff1a; 7. 静态…

考研踩坑经验分享

文章目录 写在前面自身情况简介自身学习路线优点坑点 学习路线建议1、2和3月份3、4和5月份6、7和8月份9、10月份11、12月份 一些私货建议结尾 写在前面 考研是一件非常有盼头的事&#xff0c;但绝对不是一件容易的事。 如果你不能做好来年三月份出成绩时&#xff0c;坦然接受…

Java全局异常处理,@ControllerAdvice异常拦截原理解析【简单易懂】

https://www.bilibili.com/video/BV1sS411c7Mo 文章目录 一、全局异常处理器的类型1-1、实现方式一1-2、实现方式二 二、全局异常拦截点2-1、入口2-2、全局异常拦截器是如何注入到 DispatcherServlet 的 三、ControllerAdvice 如何解析、执行3-1、解析3-2、执行 四、其它4-1、设…