用PIC16F877A的一个I/O口检测电压问题!
用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;
PORTA=0x20; //0010 0000
delay(2);
PORTD=table;
PORTA=0x10; //0001 0000
delay(2);
PORTD=table;
PORTA=0x08; //0000 1000
delay(2);
PORTD=table;
PORTA=0x04; //0000 0100
delay(2);
} 你配置了ADCON0=0x41(选择AN0通道,ADC开启),但ADCON1=0x8E的配置可能导致参考电压不明确(默认VDD和VSS作为参考,需确认硬件连接)。
未配置ADC时钟(ADCON0的时钟位未设置),可能导致采样速度不稳定。 电压比较逻辑错误:
if(a1=d)是赋值操作而非比较(应为if(a1==d)),导致条件***为真。
a1是ADC结果的千位数(0~5),直接与d=5比较不够精确,可能因噪声或误差导致判断失败。 RE0输出控制问题:
未清除RE0的其他位(PORTE是8位端口),直接赋值RE0=1可能无效(需使用PORTEbits.RE0=1或位操作)。 显示函数干扰:
disp()函数中频繁操作PORTA和PORTD,可能影响RE0的状态(需确认硬件设计是否冲突)。 你试试下面的代码
#include <xc.h>
#include <stdint.h>
#define _XTAL_FREQ 4000000// 假设使用4MHz晶振
// 函数声明
void init();
uint16_t get_ad();
void disp(uint8_t num1, uint8_t num2, uint8_t num3, uint8_t num4);
void delay(uint16_t x);
void main() {
uint16_t ad_value;
float voltage;
init();
while(1) {
ad_value = get_ad(); // 获取ADC原始值
voltage = (ad_value / 1023.0) * 5.0;// 计算实际电压值
// 显示电压(千分位,如5.000V)
uint8_t a1 = (uint16_t)(voltage * 1000) / 1000;
uint8_t a2 = ((uint16_t)(voltage * 1000) % 1000) / 100;
uint8_t a3 = ((uint16_t)(voltage * 1000) % 100) / 10;
uint8_t a4 = (uint16_t)(voltage * 1000) % 10;
disp(a1, a2, a3, a4);
// 检测电压是否接近5V(考虑误差,如4.95V~5.05V)
if (voltage >= 4.95 && voltage <= 5.05) {
PORTEbits.RE0 = 1;// RE0输出高电平
} else {
PORTEbits.RE0 = 0;// 其他情况输出低电平
}
__delay_ms(100);// 延时防抖动
}
}
void init() {
TRISA = 0x01; // RA0为输入(ADC),其他为输出
TRISE = 0x00; // RE0为输出
PORTA = 0x00;
PORTE = 0x00;
// 配置ADC:Fosc/8时钟,右对齐,AN0通道,VDD/VSS参考电压
ADCON0 = 0x41; // 01000001: 开启ADC,选择AN0
ADCON1 = 0x80; // 10000000: 右对齐,VDD/VSS参考
__delay_ms(10);// 等待ADC稳定
}
uint16_t get_ad() {
GO_nDONE = 1; // 启动ADC转换
while (GO_nDONE); // 等待转换完成
return ((ADRESH << 8) | ADRESL);// 返回10位ADC结果
}
// 显示函数(需根据实际硬件调整)
void disp(uint8_t num1, uint8_t num2, uint8_t num3, uint8_t num4) {
// 假设使用共阳数码管,table为段码表
extern const uint8_t table[];
PORTD = table;
PORTA = 0x20;// 第1位数码管使能
__delay_ms(2);
// ...(其他位显示类似)
}
void delay(uint16_t x) {
for (uint16_t a = x; a > 0; a--)
for (uint16_t b = 110; b > 0; b--);
} 关键改进点
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无硬件冲突)。 硬件检查建议
确认RA0(AN0)输入电压范围(0~5V)。
检查RE0引脚是否连接正确(无外部下拉电阻或短路)。
验证ADC参考电压是否稳定(如VDD=5V)。
如果问题仍未解决,建议用示波器测量RE0引脚输出或通过调试工具检查voltage的实际计算值。 错误太多,你根据上面的仔细看看吧。
页:
[1]