找回密码
 立即注册
查看: 122|回复: 9

8H1K17T 双路ADC检测 | 已解决

[复制链接]
  • 打卡等级:偶尔看看I
  • 打卡总天数:10
  • 最近打卡:2025-04-17 01:59:50
已绑定手机

6

主题

18

回帖

98

积分

注册会员

积分
98
发表于 2025-4-9 14:31:44 | 显示全部楼层 |阅读模式
  1. // 头文件
  2. #include "STC8H.H"                              // 引入STC8系列单片机的头文件
  3. #include "intrins.h"                            // 引入Keil的内部函数头文件
  4. // 数据存储
  5. #define HIGH_THRESHOLD 3000                     // 亮度变暗的上阈值
  6. #define LOW_THRESHOLD  2900                     // 亮度变亮的下阈值
  7. #define HIGH_Voltage   819                      // 1V
  8. #define LOW_Voltage    573                      // 0.7V
  9. #define STABLE_COUNT   20                       // 设定连续检测 20 次才切换状态
  10. // 端口定义
  11. sbit LED    = P5^4;                             // LED
  12. sbit DELAY  = P3^5;                             // 继电器
  13. sbit GM     = P3^3;                             // 定义AD光敏输入端口
  14. sbit HP     = P1^3;                             // 电网电压
  15. sbit PH0    = P1^0;                             // 主
  16. sbit PH1    = P1^1;                             // 从
  17. /*-------------------------------------------光敏探头ADC检测-----------------------------------------------------*/
  18. // 1ms延时函数
  19. void delay_ms(uint16 x)
  20. {  
  21.     uint16 j, i;   
  22.     for(j = 0; j < x; j++)   
  23.     {
  24.         for(i = 0; i < 1580; i++);      // 延时代码
  25.     }
  26. }
  27. // ADC初始化
  28. void ADC_INIT()
  29. {
  30.     ADCCFG &= ~0x0f;            // 50KSPS
  31.     ADCCFG |= 0x02;             // SPEED(2)
  32.     ADCTIM = 0x35;              // CSSETUP(0), CSHOLD(1), SMPDUTY(21)
  33.     ADC_CONTR&=0xDF;            // 清AD转换完成标志
  34.     EADC = 0;                   // 禁止ADC中断
  35.     ADCCFG|=0x20;               // ADC转换结果12位数
  36.     ADC_CONTR|=0x40;            //启动AD转换,ADC_START=1
  37. }
  38. // ADC口检测AD转换值函数
  39. uint16 GET_ADC_DATA(void)
  40. {
  41.     uint16 AD_DATA = 0;         // ADC数据存储位
  42.     ADC_CONTR&=0xDF;            // 清AD转换完成标志
  43.     ADC_CONTR&=0xBF;            // 关闭AD转换,ADC_START=0
  44.     // 数据高八位存RES 低2位存RESL
  45.     AD_DATA = ADC_RES;          // 首先读取高八位的数值
  46.     AD_DATA <<= 8;
  47.     AD_DATA|= ADC_RESL;         // 读取低4位
  48.     ADC_CONTR|=0x40;            //启动AD转换,ADC_START=1
  49.     return  AD_DATA;
  50. }
  51. // 转换ADC电压值
  52. void datapros()
  53. {
  54.     static uint16 stable_counter = 0;               // 计数器
  55.     static bit light_on = 0;                        // 当前灯的状态  
  56.     uint16 temp = GET_ADC_DATA();  
  57.     uint16 voltage = (((float)temp / 4095) * 4095);
  58.     // 记录状态是否需要改变
  59.     bit new_state = light_on;
  60.     if (!light_on && voltage > HIGH_THRESHOLD)      // 低亮度,尝试开灯
  61.     {
  62.         new_state = 1;
  63.     }
  64.     else if (light_on && voltage < LOW_THRESHOLD)   // 高亮度,尝试关灯
  65.     {
  66.         new_state = 0;
  67.     }
  68.     // 仅在状态需要改变时,进行稳定性检查
  69.     if (new_state != light_on)
  70.     {
  71.         stable_counter++;                           // 状态变化时,增加稳定计数
  72.         if (stable_counter >= STABLE_COUNT)         // 只有状态连续 N 次不变,才真正执行
  73.         {
  74.             light_on = new_state;
  75.             if(light_on == 0)                       // 检测需要关闭灯
  76.             {
  77.                 PH0 = 0;                            // 主
  78.                 PH1 = 0;                            // 从
  79.                 LED = 0;
  80.                 DELAY = 0;
  81.             }
  82.             else if(light_on == 1)
  83.             {
  84.                 LED = 1;
  85.                 DELAY = 1;
  86.             }
  87.             stable_counter = 0;                     // 计数器归零
  88.         }
  89.     }
  90.     else
  91.     {
  92.         stable_counter = 0;                         // 状态没有变化,重置计数
  93.     }
  94. }
  95. // HP转换ADC电压值----电网电压检测
  96. void HPdatapros()
  97. {
  98.     static uint16 stable_counter = 0;               // 计数器
  99.     static bit light_on = 0;                        // 当前灯的状态   
  100.     bit new_state = light_on;                       // 记录状态是否需要改变
  101.     uint16 temp = GET_ADC_DATA();  
  102.     uint16 voltage = (((float)temp / 4095) * 4095);
  103.     if(voltage > HIGH_Voltage)                      // 电网电压超过1V
  104.     {
  105.         PH0 = 0;                                    // 主
  106.         PH1 = 0;                                    // 从
  107.     }
  108.     if (light_on && voltage > LOW_Voltage)          // 电网电压超过0.7V
  109.     {
  110.         new_state = 0;
  111.     }
  112.     // 仅在状态需要改变时,进行稳定性检查
  113.     if (new_state != light_on)
  114.     {
  115.         stable_counter++;                           // 状态变化时,增加稳定计数
  116.         if (stable_counter >= STABLE_COUNT)         // 只有状态连续 N 次不变,才真正执行
  117.         {
  118.             light_on = new_state;
  119.             if(light_on == 0)                       // 检测需要关闭高压
  120.             {
  121.                 PH0 = 0;                            // 主
  122.                 PH1 = 0;                            // 从
  123.                 delay_ms(5000);                     // 5s
  124.                 PH0 = 1;                            // 主
  125.                 PH1 = 1;                            // 从
  126.             }
  127.             stable_counter = 0;                     // 计数器归零
  128.         }
  129.     }
  130.     else
  131.     {
  132.         stable_counter = 0;                         // 状态没有变化,重置计数
  133.     }
  134. }
  135. /*-------------------------------------------光敏探头 电网电压ADC检测------------------------------------------------*/
  136. // 系统初始化
  137. void system_init()
  138. {
  139.     delay_ms(1000);                     // 延时1s 待市电稳定
  140.     // 引脚定义
  141.     P3M0 |= 0x20; P3M1 &= ~0x20;        // P35 强推挽
  142.     P5M0 |= 0x10; P5M1 &= ~0x10;        // P54 强推挽
  143.     P1M0 |= 0x03; P1M1 &= ~0x03;        // P10 11 强推挽
  144.     LED = 0;                            // 关灯
  145.     DELAY = 0;                          // 继电器打开
  146.     PH0 = 0;                            // 主
  147.     PH1 = 0;                            // 从
  148.     ADC_INIT();                         // ADC初始化
  149. }
  150. void main()
  151. {
  152.     system_init();
  153.     while(1)
  154.     {
  155.         ADC_CONTR = 0x8B;
  156.         datapros();
  157.         ADC_CONTR = 0x83;            // ADC3
  158.         //HPdatapros();                // 电网电压实时检测
  159.     }
  160. }
复制代码


现在的问题是,当我没有调用电网电压检测的两行代码时 光敏检测是正常的
但是一旦调用会导致LED delay 包括PH0 1四个全部都变成低电平
原来的光敏也不起作用,这个时候电网电压检测引脚是接地的 也就是0V
正常不应该会影响到

代码写的不好,大佬高抬贵手给看看如何能保证这两个检测互不干扰
回复

使用道具 举报 送花

3

主题

1160

回帖

1031

积分

等待验证会员

积分
1031
发表于 2025-4-9 14:33:00 | 显示全部楼层
回复:关于STC8H1K17T双路ADC检测的代码分析与优化建议

1. 代码概述
该代码基于STC8H1K17T单片机,实现了双路ADC检测功能,主要用于光敏传感器和电网电压的检测。通过设定阈值和稳定计数,实现了对亮度变化和电压状态的判断,并控制LED和继电器的输出。

2. 代码分析
2.1 头文件引入
  1. c
  2. include "STC8H.H"  // 引入STC8系列单片机的头文件
  3. include "intrins.h"  // 引入Keil的内部函数头文件
复制代码
STC8H.H 是STC8系列单片机的专用头文件,包含了寄存器和外设的定义。
intrins.h 提供了Keil编译器的内部函数,如延时函数 nop() 等。

2.2 数据存储与阈值定义
  1. c
  2. define HIGHTHRESHOLD 3000  // 亮度变暗的上阈值
  3. define LOWTHRESHOLD  2900  // 亮度变亮的下阈值
  4. define HIGHVoltage   819   // 1V
  5. define LOWVoltage    573   // 0.7V
  6. define STABLECOUNT   20    // 设定连续检测 20 次才切换状态
复制代码
HIGHTHRESHOLD 和 LOWTHRESHOLD 用于判断光敏传感器的亮度变化。
HIGHVoltage 和 LOWVoltage 用于判断电网电压的状态。
STABLECOUNT 用于确保状态切换的稳定性,避免误判。

2.3 端口定义
  1. c
  2. sbit LED    = P5^4;  // LED
  3. sbit DELAY  = P3^5;  // 继电器
  4. sbit GM     = P3^3;  // 定义AD光敏输入端口
  5. sbit HP     = P1^3;  // 电网电压
  6. sbit PH0    = P1^0;  // 主
  7. 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检测功能,但在注释、结构化和错误处理等方面还有优化空间。通过上述建议,可以进一步提高代码的质量和系统的稳定性。

如需进一步的技术支持或代码优化,请随时联系。

注意:以上回复基于提供的代码片段,未涉及具体实现细节。如有更多需求或问题,欢迎进一步交流。

[本文内容由国芯人工智能辅助生成,仅供参考]
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:偶尔看看I
  • 打卡总天数:10
  • 最近打卡:2025-04-17 01:59:50
已绑定手机

6

主题

18

回帖

98

积分

注册会员

积分
98
发表于 2025-4-9 15:23:18 | 显示全部楼层
这个代码主要是为了,先执行电网电压检测,只有低于0.7V的时候才正常工作光敏的,然后高于0.7V就停5s再开,电网电压超过1V整个设备才关机这样子

原来是为了控制高压发生器,一旦短路到了0.7V,我就把高压发生器停掉,但是灯和继电器不停

然后超过1V说明设备异常 整个设备才关机
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:424
  • 最近打卡:2025-05-02 14:37:11
已绑定手机

77

主题

4849

回帖

8382

积分

超级版主

DebugLab

积分
8382
发表于 2025-4-9 16:49:41 | 显示全部楼层
截图202504091647557052.jpg
给static变量赋值,每次进入这个函数都会被赋值(程序中是清零),那static就没有意义了
你的程序要去掉=0,如需要初始化清零,这个变量放在data,用startup.a51初始化(放在xdata要修改startup.a51)
或声明为全局变量,在函数外初始化仅赋值1次,注意不能声明时赋值
另外你的程序缺少打开EAXFR,初始化就打开,不要再关闭
https://www.stcaimcu.com/forum.php?mod=viewthread&tid=16535



DebugLab
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:偶尔看看III
  • 打卡总天数:51
  • 最近打卡:2025-05-02 10:07:51

73

主题

5883

回帖

1万

积分

超级版主

积分
12079
发表于 2025-4-9 17:30:45 | 显示全部楼层
你的程序中,启动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);  //读取并返回结果
}
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:偶尔看看I
  • 打卡总天数:10
  • 最近打卡:2025-04-17 01:59:50
已绑定手机

6

主题

18

回帖

98

积分

注册会员

积分
98
发表于 2025-4-9 23:59:07 | 显示全部楼层
已解决,转换问题导致的,一个通道没发现问题,两个通道就出事了

点评

你的程序中,启动ADC后没有等待ADC完成就读取数据,才会导致错误,请参考我上面5楼的贴。  详情 回复 发表于 2025-4-10 10:24
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:343
  • 最近打卡:2025-05-02 13:52:41
已绑定手机

6

主题

202

回帖

814

积分

高级会员

积分
814
发表于 2025-4-10 05:55:11 | 显示全部楼层
感谢楼主分享,学习一下
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:偶尔看看III
  • 打卡总天数:51
  • 最近打卡:2025-05-02 10:07:51

73

主题

5883

回帖

1万

积分

超级版主

积分
12079
发表于 2025-4-10 10:24:36 | 显示全部楼层
zpzo*** 发表于 2025-4-9 23:59
已解决,转换问题导致的,一个通道没发现问题,两个通道就出事了

你的程序中,启动ADC后没有等待ADC完成就读取数据,才会导致错误,请参考我上面5楼的贴。
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:偶尔看看I
  • 打卡总天数:10
  • 最近打卡:2025-04-17 01:59:50
已绑定手机

6

主题

18

回帖

98

积分

注册会员

积分
98
发表于 2025-4-10 17:40:05 | 显示全部楼层
// 头文件
#include "STC8H.H"                                  // 引入STC8系列单片机的头文件
#include "intrins.h"                                // 引入Keil的内部函数头文件


// 宏定义
// 数据存储
#define HIGH_THRESHOLD 4000                         // 亮度变暗的上阈值
#define LOW_THRESHOLD  3900                         // 亮度变亮的下阈值
#define HIGH_HP 1000                                // 1V
#define LOW_HP  700                                 // 0.7V
#define STABLE_COUNT   20                           // 设定连续检测 20 次才切换状态
#define ADC_CHANNEL_GM 11                           // 光敏 ADC 通道
#define ADC_CHANNEL_HP 3                            // 电网 ADC 通道
// 数据类型
#define  uint32   unsigned long                     // 定义32位无符号整数类型
#define  uint16   unsigned int                      // 定义16位无符号整数类型
#define  uint8    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);  // 电网通道
    }
}



这是我的写法 一个通道对应一个数据处理函数 然后可以直接用数字传入通道 并且通道检测不会相互冲突
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:偶尔看看I
  • 打卡总天数:10
  • 最近打卡:2025-04-17 01:59:50
已绑定手机

6

主题

18

回帖

98

积分

注册会员

积分
98
发表于 2025-4-10 17:40:54 | 显示全部楼层
zpzo*** 发表于 2025-4-10 17:40
// 头文件
#include "STC8H.H"                                  // 引入STC8系列单片机的头文件
#include ...

这样就可以保证双路以及多路检测都可以运行了
回复 支持 反对

使用道具 举报 送花

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|小黑屋|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2025-5-2 18:06 , Processed in 0.198029 second(s), 116 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表