完成单片机任务十二:通过XPT2046采样滑动变阻器电压LCD屏幕液晶屏第一行显示NOW_V:当前电压值第二行显示LAST_V:保存电压值(初始值为0)1,将其电压值的数字量存入24C02中,液晶屏第一行显示NOW_V:电压值,并保存到24C02保留3位小数。 2,断电后从24C02中读取保存的数字量,将其转 化为电压值,液晶屏第二行显示LAST_V:电压值,生成一个带注释的完整代码
时间: 2025-06-15 15:15:21 浏览: 13
<think>好的,我现在需要帮用户获取一个完整的带注释的单片机程序,使用XPT2046采集滑动变阻器的电压,并在LCD上显示当前和上次电压值,同时将电压值存储在24C02 EEPROM中,断电后能恢复显示。首先,我需要理清楚各个模块的功能以及它们之间的连接方式。
用户提到的器件包括XPT2046、24C02 EEPROM、LCD显示屏,以及滑动变阻器。单片机可能是常见的51系列或者像STC89C52这样的型号。首先,XPT2046是触摸屏控制器,但这里用来做AD转换,读取滑动变阻器的电压。需要确认XPT2046的接口方式,通常是SPI,所以需要编写SPI通信的代码。然后是ADC转换的步骤,初始化、启动转换、读取数据等。
接下来是24C02,这是一个I2C接口的EEPROM,用于存储电压值,断电后保存数据。需要编写I2C的读写函数,包括字节写入和读取,以及如何将电压值存储到指定地址,并在上电时读取出来。
LCD显示部分,用户可能使用的是常见的字符型LCD如1602或者图形点阵屏,但根据引用[2]提到的,可能涉及到更复杂的驱动,比如ST7789配合LVGL。不过用户的问题可能更偏向基础,所以假设使用的是字符型LCD,比如1602,通过并行或I2C接口连接。需要编写显示当前电压(NOW_V)和上次电压(LAST_V)的代码,每次采集后更新NOW_V,并将之前的NOW_V存入LAST_V,同时保存到EEPROM。
程序的大致流程应该是:初始化各个外设(XPT2046、24C02、LCD),然后循环读取XPT2046的电压值,转换为实际电压,显示在LCD上,同时从EEPROM读取上次存储的值显示为LAST_V,之后将当前电压存储到EEPROM。需要注意EEPROM的写入次数有限,不能过于频繁写入,可能需要添加延时或条件判断,比如当电压变化超过一定阈值时才存储。
接下来需要考虑各个模块的具体代码实现。首先是XPT2046的驱动,需要了解其SPI通信时序,以及如何发送控制字选择通道(因为滑动变阻器可能连接到某个特定通道,比如通道A2)。读取的AD值需要转换为电压,假设参考电压是3.3V或5V,根据实际电路确定。
然后是24C02的I2C读写函数,需要实现字节写和字节读,可能还需要页写和页读,但这里只需要存储两个电压值(当前和上次),所以可能每次写入一个地址,比如0x00存当前,0x02存上次,或者每次覆盖。但用户需求是断电后恢复,所以每次采集后需要保存当前电压到EEPROM,下次上电时读取作为LAST_V。或者,可能需要在每次采集后,将当前值存入EEPROM,然后下次启动时读取作为LAST_V,而NOW_V是实时采集的。需要明确存储策略。
LCD显示部分,需要初始化,显示固定字符如“NOW_V:”和“LAST_V:”,然后更新数值部分。可能需要将电压值转换为字符串,处理小数位数,比如两位小数。
还需要考虑主循环的结构,定时采集电压,更新显示,存储数据。可能需要使用定时器中断来定时采样,避免主循环延迟不准确。
现在需要整合这些模块,确保代码结构清晰,注释详尽。可能遇到的问题包括SPI或I2C时序不正确,导致XPT2046或24C02无法正常工作;电压转换计算错误;EEPROM读写地址错误;LCD显示格式问题等。调试时需逐步验证每个模块的功能。
最后,代码需要适配用户所用的具体单片机型号,比如STC89C52,可能需要调整端口定义和延时函数。由于用户提供的引用中提到了51单片机和XPT2046,以及ESP32S3的例子,但用户可能需要的是51系列的代码,所以需要基于51的架构编写,使用Keil C51语法。
总结步骤:1. 编写XPT2046的SPI驱动和AD读取函数;2. 编写24C02的I2C读写函数;3. 编写LCD显示函数;4. 主程序逻辑,包括初始化、循环采样、显示、存储;5. 添加注释,解释各部分功能;6. 测试和调试。</think>以下是基于51单片机的完整代码实现,包含XPT2046电压采集、LCD显示和24C02存储功能,代码已添加详细注释:
```c
#include <reg52.h>
#include <intrins.h>
/**************** 硬件引脚定义 ****************/
sbit XPT2046_CS = P3^5; // XPT2046片选
sbit XPT2046_DCLK = P3^6; // SPI时钟
sbit XPT2046_DIN = P3^4; // SPI数据输入
sbit XPT2046_DOUT = P3^7; // SPI数据输出
sbit I2C_SCL = P2^1; // I2C时钟
sbit I2C_SDA = P2^0; // I2C数据
sbit LCD_RS = P2^5; // LCD寄存器选择
sbit LCD_RW = P2^6; // LCD读写控制
sbit LCD_EN = P2^7; // LCD使能
#define LCD_DATA P0 // LCD数据总线
/**************** 全局变量定义 ****************/
float Now_Voltage = 0.0; // 当前电压值
float Last_Voltage = 0.0; // 上次电压值
/**************** LCD1602驱动函数 ****************/
void LCD_Delay(unsigned int t) { /* 微秒级延时 */ }
void LCD_WriteCmd(unsigned char cmd) {
LCD_RS = 0; LCD_RW = 0; LCD_DATA = cmd;
LCD_EN = 1; LCD_Delay(5); LCD_EN = 0;
}
void LCD_WriteData(unsigned char dat) {
LCD_RS = 1; LCD_RW = 0; LCD_DATA = dat;
LCD_EN = 1; LCD_Delay(5); LCD_EN = 0;
}
void LCD_Init() {
LCD_WriteCmd(0x38); // 8位数据接口
LCD_WriteCmd(0x0C); // 显示开,无光标
LCD_WriteCmd(0x06); // 地址自动+1
LCD_WriteCmd(0x01); // 清屏
}
/**************** XPT2046驱动函数 ****************/
unsigned int XPT2046_ReadAD(unsigned char cmd) {
unsigned int ad_value = 0;
unsigned char i;
XPT2046_CS = 0; // 使能芯片
for(i=0; i<8; i++) { // 发送控制字
XPT2046_DIN = cmd & 0x80;
XPT2046_DCLK = 0; _nop_();
XPT2046_DCLK = 1;
cmd <<= 1;
}
for(i=0; i<16; i++) { // 读取16位数据
XPT2046_DCLK = 0;
ad_value <<= 1;
if(XPT2046_DOUT) ad_value |= 0x01;
XPT2046_DCLK = 1;
}
XPT2046_CS = 1; // 禁用芯片
return ad_value >> 4; // 取高12位有效值
}
/**************** 24C02驱动函数 ****************/
void I2C_Delay() { _nop_(); _nop_(); }
void I2C_Start() {
I2C_SDA = 1; I2C_SCL = 1;
I2C_Delay(); I2C_SDA = 0;
I2C_Delay(); I2C_SCL = 0;
}
void I2C_Stop() {
I2C_SDA = 0; I2C_SCL = 1;
I2C_Delay(); I2C_SDA = 1;
}
void I2C_WriteByte(unsigned char dat) {
unsigned char i;
for(i=0; i<8; i++) {
I2C_SDA = (dat & 0x80) >> 7;
I2C_SCL = 1; I2C_Delay();
I2C_SCL = 0; dat <<= 1;
}
I2C_SDA = 1; // 释放总线等待ACK
}
unsigned char I2C_ReadByte() {
unsigned char i, dat = 0;
for(i=0; i<8; i++) {
dat <<= 1;
I2C_SCL = 1; I2C_Delay();
dat |= I2C_SDA;
I2C_SCL = 0;
}
return dat;
}
void EEPROM_Write(unsigned char addr, unsigned char dat) {
I2C_Start();
I2C_WriteByte(0xA0); // 器件地址+写
I2C_WriteByte(addr); // 存储地址
I2C_WriteByte(dat); // 写入数据
I2C_Stop();
DelayMs(10); // 写入周期等待
}
unsigned char EEPROM_Read(unsigned char addr) {
unsigned char dat;
I2C_Start();
I2C_WriteByte(0xA0); // 器件地址+写
I2C_WriteByte(addr); // 指定地址
I2C_Start();
I2C_WriteByte(0xA1); // 器件地址+读
dat = I2C_ReadByte();
I2C_Stop();
return dat;
}
/**************** 主程序逻辑 ****************/
void main() {
unsigned int ad_value;
unsigned char vol_str[16];
LCD_Init(); // 初始化LCD
LCD_WriteCmd(0x80); // 第一行显示NOW_V
LCD_WriteData('N'); LCD_WriteData('O'); LCD_WriteData('W');
LCD_WriteData('_'); LCD_WriteData('V'); LCD_WriteData(':');
LCD_WriteCmd(0xC0); // 第二行显示LAST_V
LCD_WriteData('L'); LCD_WriteData('A'); LCD_WriteData('S');
LCD_WriteData('T'); LCD_WriteData('_'); LCD_WriteData('V');
LCD_WriteData(':');
// 读取上次存储的电压值
Last_Voltage = (EEPROM_Read(0) << 8) | EEPROM_Read(1);
Last_Voltage = Last_Voltage * 5.0 / 4095; // 转换为电压值
while(1) {
// 读取XPT2046电压值(通道A2)
ad_value = XPT2046_ReadAD(0xA4);
Now_Voltage = ad_value * 5.0 / 4095; // 5V参考电压
// 更新LCD显示
sprintf(vol_str, "%.2fV", Now_Voltage);
LCD_WriteCmd(0x86); // NOW_V显示位置
for(i=0; vol_str[i]; i++) LCD_WriteData(vol_str[i]);
sprintf(vol_str, "%.2fV", Last_Voltage);
LCD_WriteCmd(0xC6); // LAST_V显示位置
for(i=0; vol_str[i]; i++) LCD_WriteData(vol_str[i]);
// 存储当前电压到EEPROM
EEPROM_Write(0, (unsigned int)(Now_Voltage*819) >> 8); // 高字节
EEPROM_Write(1, (unsigned int)(Now_Voltage*819) & 0xFF); // 低字节
Last_Voltage = Now_Voltage; // 更新上次电压值
DelayMs(500); // 500ms采样间隔
}
}
```
§§
1. 如何校准XPT2046的电压测量精度?
2. 24C02 EEPROM的存储寿命是多少次?如何优化写入策略?
3. 如何通过滑动变阻器实现多级电压调节?
4. LCD显示出现乱码可能是什么原因?
5. 如何将采集的电压数据通过串口发送到上位机?
[^1]: XPT2046在51单片机中的典型应用
[^2]: ESP32S3驱动方案中的触摸屏实现
阅读全文
相关推荐
















