8H1K17T 双路ADC检测 | 已解决
// 头文件#include "STC8H.H" // 引入STC8系列单片机的头文件
#include "intrins.h" // 引入Keil的内部函数头文件
// 数据存储
#define HIGH_THRESHOLD 3000 // 亮度变暗的上阈值
#define LOW_THRESHOLD2900 // 亮度变亮的下阈值
#define HIGH_Voltage 819 // 1V
#define LOW_Voltage 573 // 0.7V
#define STABLE_COUNT 20 // 设定连续检测 20 次才切换状态
// 端口定义
sbit LED = P5^4; // LED
sbit DELAY= P3^5; // 继电器
sbit GM = P3^3; // 定义AD光敏输入端口
sbit HP = P1^3; // 电网电压
sbit PH0 = P1^0; // 主
sbit PH1 = P1^1; // 从
/*-------------------------------------------光敏探头ADC检测-----------------------------------------------------*/
// 1ms延时函数
void delay_ms(uint16 x)
{
uint16 j, i;
for(j = 0; j < x; j++)
{
for(i = 0; i < 1580; i++); // 延时代码
}
}
// ADC初始化
void ADC_INIT()
{
ADCCFG &= ~0x0f; // 50KSPS
ADCCFG |= 0x02; // SPEED(2)
ADCTIM = 0x35; // CSSETUP(0), CSHOLD(1), SMPDUTY(21)
ADC_CONTR&=0xDF; // 清AD转换完成标志
EADC = 0; // 禁止ADC中断
ADCCFG|=0x20; // ADC转换结果12位数
ADC_CONTR|=0x40; //启动AD转换,ADC_START=1
}
// ADC口检测AD转换值函数
uint16 GET_ADC_DATA(void)
{
uint16 AD_DATA = 0; // ADC数据存储位
ADC_CONTR&=0xDF; // 清AD转换完成标志
ADC_CONTR&=0xBF; // 关闭AD转换,ADC_START=0
// 数据高八位存RES 低2位存RESL
AD_DATA = ADC_RES; // 首先读取高八位的数值
AD_DATA <<= 8;
AD_DATA|= ADC_RESL; // 读取低4位
ADC_CONTR|=0x40; //启动AD转换,ADC_START=1
returnAD_DATA;
}
// 转换ADC电压值
void datapros()
{
static uint16 stable_counter = 0; // 计数器
static bit light_on = 0; // 当前灯的状态
uint16 temp = GET_ADC_DATA();
uint16 voltage = (((float)temp / 4095) * 4095);
// 记录状态是否需要改变
bit new_state = light_on;
if (!light_on && voltage > HIGH_THRESHOLD) // 低亮度,尝试开灯
{
new_state = 1;
}
else if (light_on && voltage < LOW_THRESHOLD) // 高亮度,尝试关灯
{
new_state = 0;
}
// 仅在状态需要改变时,进行稳定性检查
if (new_state != light_on)
{
stable_counter++; // 状态变化时,增加稳定计数
if (stable_counter >= STABLE_COUNT) // 只有状态连续 N 次不变,才真正执行
{
light_on = new_state;
if(light_on == 0) // 检测需要关闭灯
{
PH0 = 0; // 主
PH1 = 0; // 从
LED = 0;
DELAY = 0;
}
else if(light_on == 1)
{
LED = 1;
DELAY = 1;
}
stable_counter = 0; // 计数器归零
}
}
else
{
stable_counter = 0; // 状态没有变化,重置计数
}
}
// HP转换ADC电压值----电网电压检测
void HPdatapros()
{
static uint16 stable_counter = 0; // 计数器
static bit light_on = 0; // 当前灯的状态
bit new_state = light_on; // 记录状态是否需要改变
uint16 temp = GET_ADC_DATA();
uint16 voltage = (((float)temp / 4095) * 4095);
if(voltage > HIGH_Voltage) // 电网电压超过1V
{
PH0 = 0; // 主
PH1 = 0; // 从
}
if (light_on && voltage > LOW_Voltage) // 电网电压超过0.7V
{
new_state = 0;
}
// 仅在状态需要改变时,进行稳定性检查
if (new_state != light_on)
{
stable_counter++; // 状态变化时,增加稳定计数
if (stable_counter >= STABLE_COUNT) // 只有状态连续 N 次不变,才真正执行
{
light_on = new_state;
if(light_on == 0) // 检测需要关闭高压
{
PH0 = 0; // 主
PH1 = 0; // 从
delay_ms(5000); // 5s
PH0 = 1; // 主
PH1 = 1; // 从
}
stable_counter = 0; // 计数器归零
}
}
else
{
stable_counter = 0; // 状态没有变化,重置计数
}
}
/*-------------------------------------------光敏探头 电网电压ADC检测------------------------------------------------*/
// 系统初始化
void system_init()
{
delay_ms(1000); // 延时1s 待市电稳定
// 引脚定义
P3M0 |= 0x20; P3M1 &= ~0x20; // P35 强推挽
P5M0 |= 0x10; P5M1 &= ~0x10; // P54 强推挽
P1M0 |= 0x03; P1M1 &= ~0x03; // P10 11 强推挽
LED = 0; // 关灯
DELAY = 0; // 继电器打开
PH0 = 0; // 主
PH1 = 0; // 从
ADC_INIT(); // ADC初始化
}
void main()
{
system_init();
while(1)
{
ADC_CONTR = 0x8B;
datapros();
ADC_CONTR = 0x83; // ADC3
//HPdatapros(); // 电网电压实时检测
}
}
现在的问题是,当我没有调用电网电压检测的两行代码时 光敏检测是正常的
但是一旦调用会导致LED delay 包括PH0 1四个全部都变成低电平
原来的光敏也不起作用,这个时候电网电压检测引脚是接地的 也就是0V
正常不应该会影响到
代码写的不好,大佬高抬贵手给看看如何能保证这两个检测互不干扰
回复:关于STC8H1K17T双路ADC检测的代码分析与优化建议
1. 代码概述
该代码基于STC8H1K17T单片机,实现了双路ADC检测功能,主要用于光敏传感器和电网电压的检测。通过设定阈值和稳定计数,实现了对亮度变化和电压状态的判断,并控制LED和继电器的输出。
2. 代码分析
2.1 头文件引入
c
include "STC8H.H"// 引入STC8系列单片机的头文件
include "intrins.h"// 引入Keil的内部函数头文件
STC8H.H 是STC8系列单片机的专用头文件,包含了寄存器和外设的定义。
intrins.h 提供了Keil编译器的内部函数,如延时函数 nop() 等。
2.2 数据存储与阈值定义
c
define HIGHTHRESHOLD 3000// 亮度变暗的上阈值
define LOWTHRESHOLD2900// 亮度变亮的下阈值
define HIGHVoltage 819 // 1V
define LOWVoltage 573 // 0.7V
define STABLECOUNT 20 // 设定连续检测 20 次才切换状态
HIGHTHRESHOLD 和 LOWTHRESHOLD 用于判断光敏传感器的亮度变化。
HIGHVoltage 和 LOWVoltage 用于判断电网电压的状态。
STABLECOUNT 用于确保状态切换的稳定性,避免误判。
2.3 端口定义
c
sbit LED = P5^4;// LED
sbit DELAY= P3^5;// 继电器
sbit GM = P3^3;// 定义AD光敏输入端口
sbit HP = P1^3;// 电网电压
sbit PH0 = P1^0;// 主
sbit PH1 = P1^1;// 主
LED 和 DELAY 分别控制LED和继电器的输出。
GM 和 HP 分别用于光敏传感器和电网电压的ADC输入。
PH0 和 PH1 可能用于其他功能,但未在代码中明确说明。
3. 优化建议
3.1 增加注释
建议在代码中增加更多注释,特别是对关键逻辑和寄存器配置的说明,以提高代码的可读性和可维护性。
3.2 状态机设计
可以考虑使用状态机来管理亮度变化和电压状态的切换,以提高代码的结构性和可扩展性。
3.3 参数化配置
将阈值和稳定计数等参数定义为宏或常量,方便后续调整和优化。
3.4 错误处理
增加对ADC采样结果的错误处理机制,如超时检测或异常值过滤,以提高系统的鲁棒性。
3.5 代码模块化
将ADC采样、状态判断和输出控制等功能模块化,便于代码的复用和测试。
4. 总结
该代码实现了基本的双路ADC检测功能,但在注释、结构化和错误处理等方面还有优化空间。通过上述建议,可以进一步提高代码的质量和系统的稳定性。
如需进一步的技术支持或代码优化,请随时联系。
注意:以上回复基于提供的代码片段,未涉及具体实现细节。如有更多需求或问题,欢迎进一步交流。
[本文内容由国芯人工智能辅助生成,仅供参考] 这个代码主要是为了,先执行电网电压检测,只有低于0.7V的时候才正常工作光敏的,然后高于0.7V就停5s再开,电网电压超过1V整个设备才关机这样子
原来是为了控制高压发生器,一旦短路到了0.7V,我就把高压发生器停掉,但是灯和继电器不停
然后超过1V说明设备异常 整个设备才关机
给static变量赋值,每次进入这个函数都会被赋值(程序中是清零),那static就没有意义了
你的程序要去掉=0,如需要初始化清零,这个变量放在data,用startup.a51初始化(放在xdata要修改startup.a51)
或声明为全局变量,在函数外初始化仅赋值1次,注意不能声明时赋值
另外你的程序缺少打开EAXFR,初始化就打开,不要再关闭
https://www.stcaimcu.com/forum.php?mod=viewthread&tid=16535
你的程序中,启动ADC后没有等待检测到ADC完成就读取数据,这是不对的。
初始化时,不要启动ADC转换。
// ADC初始化
void ADC_INIT()
{
ADCCFG &= ~0x0f; // 50KSPS
ADCCFG |= 0x02; // SPEED(2)
ADCTIM = 0x35; // CSSETUP(0), CSHOLD(1), SMPDUTY(21)
ADC_CONTR&=0xDF; // 清AD转换完成标志
EADC = 0; // 禁止ADC中断
ADCCFG|=0x20; // ADC转换结果12位数
// ADC_CONTR|=0x40; //不要启动AD转换!!!!!!!!!!!!!
}
在读取函数启动ADC转换并等待完成,再读数据。
// ADC口检测AD转换值函数
uint16 GET_ADC_DATA(void)
{
uint16 AD_DATA; // ADC数据存储位
ADC_CONTR|=0x40; //启动AD转换!
NOP(5); //加5个NOP
while((ADC_CONTR & 0x20) == 0); //等待转换完成
ADC_CONTR&=0xDF; // 清AD转换完成标志
//ADC_CONTR&=0xBF; // 不用清ADC_START=0, 自动清0的
return(((uint16)ADC_RES << 8) + ADC_RESL);//读取并返回结果
}
已解决,转换问题导致的,一个通道没发现问题,两个通道就出事了 感谢楼主分享,学习一下 zpzobcna 发表于 2025-4-9 23:59
已解决,转换问题导致的,一个通道没发现问题,两个通道就出事了
你的程序中,启动ADC后没有等待ADC完成就读取数据,才会导致错误,请参考我上面5楼的贴。 // 头文件
#include "STC8H.H" // 引入STC8系列单片机的头文件
#include "intrins.h" // 引入Keil的内部函数头文件
// 宏定义
// 数据存储
#define HIGH_THRESHOLD 4000 // 亮度变暗的上阈值
#define LOW_THRESHOLD3900 // 亮度变亮的下阈值
#define HIGH_HP 1000 // 1V
#define LOW_HP700 // 0.7V
#define STABLE_COUNT 20 // 设定连续检测 20 次才切换状态
#define ADC_CHANNEL_GM 11 // 光敏 ADC 通道
#define ADC_CHANNEL_HP 3 // 电网 ADC 通道
// 数据类型
#defineuint32 unsigned long // 定义32位无符号整数类型
#defineuint16 unsigned int // 定义16位无符号整数类型
#defineuint8 unsigned char // 定义8位无符号整数类型
// 端口定义
sbit LED = P5^4; // LED
sbit DELAY= P3^5; // 继电器
sbit GM = P3^3; // 定义AD光敏输入端口
sbit HP = P1^3; // 电网电压
sbit PH0 = P1^0; // 主
sbit PH1 = P1^1; // 从
// 1ms延时函数
void delay_ms(uint16 x)
{
uint16 j, i;
for(j = 0; j < x; j++)
{
for(i = 0; i < 1580; i++); // 延时代码
}
}
// ADC初始化
void ADC_INIT()
{
ADC_CONTR |= 0x80; // 打开ADC电源
ADCCFG &= ~0x0f; // 清除速度选择位
ADCCFG |= 0x02; // 设置采样速率为 SPEED=2,即 50KSPS
ADCTIM = 0x35; // CSSETUP(0), CSHOLD(1), SMPDUTY(21)
ADC_CONTR &= 0xDF; // 清AD转换完成标志
EADC = 0; // 禁止ADC中断
ADCCFG |= 0x20; // ADC转换结果12位数
}
// ADC口检测AD转换值函数
uint16 ADC_ReadChannel(uint8 channel)
{
uint16 result;
ADC_CONTR &= 0xF0; // 清通道选择位
ADC_CONTR |= (channel & 0x0F); // 设置通道
ADC_CONTR &= ~0x20; // 清完成标志
ADC_CONTR |= 0x40; // 启动转换
while (!(ADC_CONTR & 0x20)); // 等待完成
ADC_CONTR &= ~0x20; // 清完成标志
result = ADC_RES; // 首先读取高八位的数值
result <<= 8;
result|= ADC_RESL; // 读取低4位
return result;
}
// 光敏
void process_gm(uint8 channel)
{
static uint16 gm_stable_counter = 0;
static bit gm_light_on = 0;
uint16 temp = ADC_ReadChannel(channel);// 用传入的通道号
uint16 voltage = (uint32)temp * 5000 / 4095;
bit new_state = gm_light_on;
if (!gm_light_on && voltage > HIGH_THRESHOLD)
{
new_state = 1;
}
else if (gm_light_on && voltage < LOW_THRESHOLD)
{
new_state = 0;
}
if (new_state != gm_light_on)
{
gm_stable_counter++;
if (gm_stable_counter >= STABLE_COUNT)
{
gm_light_on = new_state;
LED = gm_light_on;
DELAY = gm_light_on;
gm_stable_counter = 0;
}
}
else
{
gm_stable_counter = 0;
}
}
void process_hp(uint8 channel)
{
static uint16 hp_stable_counter = 0;
static bit hp_light_on = 0;
uint16 temp = ADC_ReadChannel(channel);// 用传入的通道号
uint16 voltage = (uint32)temp * 5000 / 4095;
bit new_state = hp_light_on;
if (!hp_light_on && voltage > HIGH_HP) // 超过1V
{
new_state = 1;
}
else if (hp_light_on && voltage < LOW_HP) // 超过0.7V
{
new_state = 0;
}
if (new_state != hp_light_on)
{
hp_stable_counter++;
if (hp_stable_counter >= STABLE_COUNT)
{
hp_light_on = new_state;
if(hp_light_on == 1) // 超过1V
{
mode = 2;
LED = 0;
DELAY = 0;
PWMA_ENO &= ~0x03;
PH0 = 0;
PH1 = 0;
}
else if(hp_light_on == 0) // 超过0.7V
{
PWMA_ENO &= ~0x03;
PH0 = 0;
PH1 = 0;
delay_ms(5000);
PWMA_ENO |= 0x03;
}
hp_stable_counter = 0;
}
}
else
{
hp_stable_counter = 0;
}
}
// 系统初始化
void system_init()
{
delay_ms(1000); // 延时1s 待市电稳定
// 引脚定义
P3M0 |= 0x20; P3M1 &= ~0x20; // P35 强推挽
P5M0 |= 0x10; P5M1 &= ~0x10; // P54 强推挽
P1M0 |= 0x03; P1M1 &= ~0x03; // P10 11 强推挽
LED = 0; // 关灯
DELAY = 0; // 继电器打开
PH0 = 0; // 主
PH1 = 0; // 从
ADC_INIT(); // ADC初始化
}
// 主函数
void main()
{
system_init();
while (1)
{
process_gm(ADC_CHANNEL_GM);// 光敏通道
process_hp(ADC_CHANNEL_HP);// 电网通道
}
}
这是我的写法 一个通道对应一个数据处理函数 然后可以直接用数字传入通道 并且通道检测不会相互冲突
zpzobcna 发表于 2025-4-10 17:40
// 头文件
#include "STC8H.H" // 引入STC8系列单片机的头文件
#include ...
这样就可以保证双路以及多路检测都可以运行了
页:
[1]