#include <reg51.h> #include <stdio.h> #define MQ135_PIN P1_0 // MQ-135??????P1.0 #define THRESHOLD 500 // ?????? // ????? void UART_Init() { TMOD = 0x20; // ???1??2 TH1 = 0xFD; // ???9600 SCON = 0x50; // 8???,????? TR1 = 1; // ?????1 } // ?????? void UART_SendChar(char c) { SBUF = c; while(!TI); TI = 0; } // ????? void UART_SendString(char *str) { while(*str) { UART_SendChar(*str++); } } // ADC??(??) unsigned int Read_ADC() { // ??????,?????ADC???? return MQ135_PIN * 1000; // ????? } void main() { unsigned int smoke_value; UART_Init(); UART_SendString("System Initialized\r\n"); while(1) { smoke_value = Read_ADC(); // ?????STM32 UART_SendChar('S'); // ???? UART_SendChar(smoke_value >> 8); // ??? UART_SendChar(smoke_value & 0xFF); // ??? UART_SendChar('E'); // ???? // ???? for(int i=0; i<30000; i++)
时间: 2025-05-25 14:14:46 浏览: 10
根据你的代码,这是一个基于8051单片机的MQ-135气体传感器读取和串口通信的程序。以下是对你代码的分析、改进以及解释。
### 问题分析
1. **ADC读取**:当前`Read_ADC`函数中直接返回了`MQ135_PIN * 1000`,这显然是不正确的,因为`MQ135_PIN`只是一个数字引脚的状态(高电平或低电平),无法直接表示模拟值。需要使用外部ADC或者单片机内置的ADC模块来读取模拟信号。
2. **UART发送数据格式**:你通过UART发送了`S`开头、`E`结尾的数据包,中间包含两个字节的烟雾值。这种协议设计是合理的,但需要确保接收端能够正确解析。
3. **延时循环**:`for(int i=0; i<30000; i++)` 是一个简单的延时函数,但这种方式不够精确且占用CPU资源。可以改用定时器实现更精确的延时。
### 改进后的代码
以下是一个改进版本的代码,假设单片机有内置ADC功能(如STC系列或其他支持ADC的8051变种):
```c
#include <reg51.h>
#include <stdio.h>
#define MQ135_PIN P1_0 // MQ-135连接到P1.0
#define THRESHOLD 500 // 阈值
// 初始化UART
void UART_Init() {
TMOD = 0x20; // 定时器1模式2
TH1 = 0xFD; // 波特率9600
SCON = 0x50; // 8位数据, 1位停止位, 允许接收
TR1 = 1; // 启动定时器1
}
// 发送单个字符
void UART_SendChar(char c) {
SBUF = c;
while(!TI); // 等待发送完成
TI = 0; // 清除发送标志
}
// 发送字符串
void UART_SendString(char *str) {
while(*str) {
UART_SendChar(*str++);
}
}
// ADC初始化 (假设使用内部ADC)
void ADC_Init() {
// 假设单片机有内置ADC,配置相关寄存器
// 这里仅作示意,具体实现依赖于硬件
ADEN = 1; // 开启ADC
ADC_CONTR = 0x84; // 选择通道0,开始转换
}
// 读取ADC值
unsigned int Read_ADC() {
unsigned int adc_value = 0;
// 模拟启动一次ADC转换
ADC_CONTR = 0x84; // 开始转换
while(ADBUSY); // 等待转换完成
// 读取结果 (假设结果存储在ADRESL和ADRESH)
adc_value = ADRESH << 8 | ADRESL;
return adc_value;
}
// 延时函数 (简化版)
void delay(unsigned int ms) {
unsigned int i, j;
for(i = 0; i < ms; i++) {
for(j = 0; j < 120; j++); // 调整内层循环次数以适应不同晶振频率
}
}
void main() {
unsigned int smoke_value;
UART_Init(); // 初始化UART
ADC_Init(); // 初始化ADC
UART_SendString("System Initialized\r\n");
while(1) {
smoke_value = Read_ADC(); // 读取ADC值
// 发送数据包
UART_SendChar('S'); // 数据包起始标志
UART_SendChar(smoke_value >> 8); // 高字节
UART_SendChar(smoke_value & 0xFF); // 低字节
UART_SendChar('E'); // 数据包结束标志
// 如果烟雾值超过阈值,发送报警信息
if(smoke_value > THRESHOLD) {
UART_SendString("Smoke detected! Value: ");
UART_SendString(smoke_value / 100 + '0'); // 简单显示数值
UART_SendString("\r\n");
}
delay(1000); // 每秒发送一次数据
}
}
```
### 代码解释
1. **UART初始化**:
- `TMOD = 0x20`:设置定时器1为模式2(8位自动重装)。
- `TH1 = 0xFD`:设置波特率为9600(假设晶振为11.0592MHz)。
- `SCON = 0x50`:配置串口为8位数据、1位停止位,并允许接收。
- `TR1 = 1`:启动定时器1。
2. **ADC初始化**:
- 假设单片机有内置ADC,配置相关寄存器以启用ADC功能。
- `ADC_CONTR = 0x84`:选择通道0并启动转换。
3. **读取ADC值**:
- 使用`ADC_CONTR`控制ADC转换。
- 读取结果时,将高8位和低8位组合成16位的ADC值。
4. **延时函数**:
- 使用双重循环实现延时,避免占用过多CPU资源。
5. **主循环**:
- 每次读取ADC值并通过UART发送。
- 如果烟雾值超过设定的阈值,则发送报警信息。
### 注意事项
- **ADC支持**:如果单片机没有内置ADC,需要使用外部ADC芯片(如PCF8591)进行模拟信号采集。
- **波特率计算**:确保根据实际晶振频率调整`TH1`的值以匹配目标波特率。
- **数据解析**:接收端需要按照`S`开头、`E`结尾的协议解析数据包。
阅读全文
相关推荐

















