[PIC32/SAM] 用PIC16F877A的一个I/O口检测电压问题!

[复制链接]
 楼主| jcky001 发表于 2025-4-12 18:23 | 显示全部楼层 |阅读模式
用PIC16F877A的一个I/O口检测电压  当检测到的电压=5V时  RE0输出高电平,帮忙看下是哪里出了问题,为什么实现不了这个功能?谢谢了
void main()
{
          uint lednum,d;
          d=5;
          uint a1,a2,a3,a4;
          init();
          while(1)
          {
                   lednum=get_ad();
                   a1=lednum/1000;
                   a2=lednum%1000/100;
                   a3=lednum%100/10;
                   a4=lednum%10;
                   disp(a1,a2,a3,a4);
                   if(a1=d)
                   {
                           RE0=1;
                   }
          }
         
}
void init()
{
          TRISA=0x01;
          TRISD=0x00;
          TRISE=0x00;
          PORTA=0X00;
          PORTD=0x00;
          PORTE=0xFF;
          ADCON0=0x41;
          ADCON1=0x8E;
          delay(10);
}
void delay(uint x)
{
uint a,b;
for(a=x;a>0;a--)
  for(b=110;b>0;b--);
}
uint get_ad()
{
        uint adval;
        float advalf;
        GO=1;
        while(GO);
        adval=ADRESH;
        adval=adval<<8|ADRESL;
        advalf=adval/1023.0*5.0;
        adval=advalf*1000;
        return (adval);
}
void disp(uchar num1,uchar num2,uchar num3,uchar num4)
{
      PORTD=table1[num1];
      PORTA=0x20;             //0010 0000
delay(2);
      PORTD=table[num2];
      PORTA=0x10;            //0001 0000
delay(2);
      PORTD=table[num3];
      PORTA=0x08;            //0000 1000
delay(2);
      PORTD=table[num4];
      PORTA=0x04;            //0000 0100
      delay(2);
}
幸福小强 发表于 2025-4-14 12:25 | 显示全部楼层
你配置了ADCON0=0x41(选择AN0通道,ADC开启),但ADCON1=0x8E的配置可能导致参考电压不明确(默认VDD和VSS作为参考,需确认硬件连接)。

未配置ADC时钟(ADCON0的时钟位未设置),可能导致采样速度不稳定。
幸福小强 发表于 2025-4-14 12:26 | 显示全部楼层
电压比较逻辑错误:

if(a1=d)是赋值操作而非比较(应为if(a1==d)),导致条件***为真。

a1是ADC结果的千位数(0~5),直接与d=5比较不够精确,可能因噪声或误差导致判断失败。
幸福小强 发表于 2025-4-14 12:26 | 显示全部楼层
RE0输出控制问题:

未清除RE0的其他位(PORTE是8位端口),直接赋值RE0=1可能无效(需使用PORTEbits.RE0=1或位操作)。
幸福小强 发表于 2025-4-14 12:26 | 显示全部楼层
显示函数干扰:

disp()函数中频繁操作PORTA和PORTD,可能影响RE0的状态(需确认硬件设计是否冲突)。
幸福小强 发表于 2025-4-14 12:26 | 显示全部楼层
你试试下面的代码
  1. #include <xc.h>
  2. #include <stdint.h>

  3. #define _XTAL_FREQ 4000000  // 假设使用4MHz晶振

  4. // 函数声明
  5. void init();
  6. uint16_t get_ad();
  7. void disp(uint8_t num1, uint8_t num2, uint8_t num3, uint8_t num4);
  8. void delay(uint16_t x);

  9. void main() {
  10.     uint16_t ad_value;
  11.     float voltage;
  12.     init();

  13.     while(1) {
  14.         ad_value = get_ad();          // 获取ADC原始值
  15.         voltage = (ad_value / 1023.0) * 5.0;  // 计算实际电压值

  16.         // 显示电压(千分位,如5.000V)
  17.         uint8_t a1 = (uint16_t)(voltage * 1000) / 1000;
  18.         uint8_t a2 = ((uint16_t)(voltage * 1000) % 1000) / 100;
  19.         uint8_t a3 = ((uint16_t)(voltage * 1000) % 100) / 10;
  20.         uint8_t a4 = (uint16_t)(voltage * 1000) % 10;
  21.         disp(a1, a2, a3, a4);

  22.         // 检测电压是否接近5V(考虑误差,如4.95V~5.05V)
  23.         if (voltage >= 4.95 && voltage <= 5.05) {
  24.             PORTEbits.RE0 = 1;  // RE0输出高电平
  25.         } else {
  26.             PORTEbits.RE0 = 0;  // 其他情况输出低电平
  27.         }
  28.         __delay_ms(100);  // 延时防抖动
  29.     }
  30. }

  31. void init() {
  32.     TRISA = 0x01;    // RA0为输入(ADC),其他为输出
  33.     TRISE = 0x00;    // RE0为输出
  34.     PORTA = 0x00;
  35.     PORTE = 0x00;

  36.     // 配置ADC:Fosc/8时钟,右对齐,AN0通道,VDD/VSS参考电压
  37.     ADCON0 = 0x41;   // 01000001: 开启ADC,选择AN0
  38.     ADCON1 = 0x80;   // 10000000: 右对齐,VDD/VSS参考
  39.     __delay_ms(10);  // 等待ADC稳定
  40. }

  41. uint16_t get_ad() {
  42.     GO_nDONE = 1;          // 启动ADC转换
  43.     while (GO_nDONE);      // 等待转换完成
  44.     return ((ADRESH << 8) | ADRESL);  // 返回10位ADC结果
  45. }

  46. // 显示函数(需根据实际硬件调整)
  47. void disp(uint8_t num1, uint8_t num2, uint8_t num3, uint8_t num4) {
  48.     // 假设使用共阳数码管,table为段码表
  49.     extern const uint8_t table[];
  50.     PORTD = table[num1];
  51.     PORTA = 0x20;  // 第1位数码管使能
  52.     __delay_ms(2);
  53.     // ...(其他位显示类似)
  54. }

  55. void delay(uint16_t x) {
  56.     for (uint16_t a = x; a > 0; a--)
  57.         for (uint16_t b = 110; b > 0; b--);
  58. }
幸福小强 发表于 2025-4-14 12:27 | 显示全部楼层
关键改进点
ADC配置修正:

明确参考电压为VDD/VSS(ADCON1=0x80)。

添加ADC稳定延时(__delay_ms(10))。

精确电压比较:

直接计算浮点电压值(voltage),并设置合理误差范围(如4.95V~5.05V)。

避免直接比较ADC结果的某一位(原代码的a1可能不准确)。

RE0正确操作:

使用PORTEbits.RE0=1确保仅控制RE0引脚。

显示与逻辑分离:

显示函数不影响RE0状态(需确认PORTD/PORTA与RE0无硬件冲突)。
幸福小强 发表于 2025-4-14 12:27 | 显示全部楼层
硬件检查建议
确认RA0(AN0)输入电压范围(0~5V)。

检查RE0引脚是否连接正确(无外部下拉电阻或短路)。

验证ADC参考电压是否稳定(如VDD=5V)。

如果问题仍未解决,建议用示波器测量RE0引脚输出或通过调试工具检查voltage的实际计算值。
幸福小强 发表于 2025-4-14 12:32 | 显示全部楼层
错误太多,你根据上面的仔细看看吧。
喂什么玩意 发表于 2025-4-25 16:08 | 显示全部楼层
你在判断a1 == d时,使用的是赋值操作符 = 而不是比较操作符 ==。应该改成if(a1 == d)。当前代码是将d的值赋给a1,然后判断其是否为真(即非零)。这可能是导致无法达到预期功能的原因之一。
喂什么玩意 发表于 2025-4-25 16:44 | 显示全部楼层
由于advalf是一个浮动值,乘以1000后再作为整数返回可能导致一些精度损失。如果你直接使用adval并进行适当的比较会更简单。
喂什么玩意 发表于 2025-4-25 16:49 | 显示全部楼层
建议在get_ad()返回值时打印调试信息,例如打印出adval的值,检查它是否接近5000,并验证电压是否正确。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

1636

主题

5575

帖子

6

粉丝
快速回复 在线客服 返回列表 返回顶部

1636

主题

5575

帖子

6

粉丝
快速回复 在线客服 返回列表 返回顶部