标题:
c51单片机PCF8591 lcd1602做的电压表显示问题
[打印本页]
作者:
kean
时间:
2018-12-17 16:16
标题:
c51单片机PCF8591 lcd1602做的电压表显示问题
整个流程为:mcu通过内部中断PWM方式产生可调输出电压,接到PCF8591的AIN3,返回uchar类型,然后通过mcu显示到lcd上。
现在问题是:不论我如何改变pwm的占空比,再或者不论PCF有没有输入都会输出4.8。之前在考虑是不是i2c读字节前需要空读,但是没有能够写出来,求助。
有思路的可以留言可以QQ联系,谢谢。
[qq]1366970820[/qq]
只要能解决,500黑币都给!
main.c
<div>#include <reg51.h> //51寄存器文件
#include <intrins.h>
#include <I2C.H>
#include"1602.h"
#define PCF8591 0x90 //PCF8591 地址</div><div>typedef unsigned int uint;//WORD代替unsigned int
typedef unsigned char uchar;
unsigned char timer0,timer1,second,second1;
unsigned int count,count1,mid;
unsigned int key;
unsigned char v,ss,aa;
unsigned long test_ss;
sbit PWM=P3^7;
unsigned int i,j;
unsigned char Data,keyFlag;
uint a,b,c;
uchar shi,ge,ms,vt;
uint a,b,c,o;
float why;</div><div>void scan_key();
int T1s();</div><div>uchar dis1[] = {"V1:"};
uchar dis2[] = {"V2:"};
uchar dis1t[] = {"T1:"};
uchar dis2t[] = {"T2:"};
uchar dist1[] = "00.0s";
uchar dist2[] = "00.0x";</div><div>void system_Ini()
{
TMOD = 0x11;
//PWM
TH0 = 0xff;
TL0 = 0xf7;
TH1 = 0xff;
TL1 = 0xf7;
EA = 1;
ET0 = 1;
ET1 = 1;
TR0 = 1;
TR1 = 1;
//IE =0x8A;
}
/*******************************************************************
ADC发送字节[命令]数据函数
*******************************************************************/
bit ISendByte(unsigned char sla,unsigned char c)
{
Start_I2c(); //启动总线
SendByte(sla); //发送器件地址
if(ack==0)return(0);
SendByte(c); //发送数据
if(ack==0)return(0);
Stop_I2c(); //结束总线
return(1);
}
/*******************************************************************
ADC读字节数据函数
*******************************************************************/
unsigned char IRcvByte(unsigned char sla)
{ unsigned char c = 0;
Start_I2c(); //启动总线
SendByte(sla+1); //发送器件地址
if(ack==0)return(0);
c=RcvByte(); //读取第1路电压值,范围是0-255
c=0;
c=RcvByte(); //读取第1路电压值,范围是0-255
//for(what=0;what<5;what++)//连续读5次,取最后一次,以便读取稳定值
Ack_I2c(1); //发送非就答位
Stop_I2c(); //结束总线
return(c);
}
main()
{
BYTE i;
//uchar shi,ge;
lcd_init(); //初始化LCD
system_Ini();
delay(10);
lcd_pos(0); //设置显示位置为第一行的第1个字符
i = 0;
while(dis1[i] != '\0')
{ //显示字符"一号电压"
lcd_wdat(dis1[i]);
i++;
}
lcd_pos(8); //设置显示位置为第一行的第9个字符
i = 0;
while(dis1[i] != '\0')
{ //显示字符"一号时间"
lcd_wdat(dis1t[i]);
i++;
}
lcd_pos(0x40); //设置显示位置为第二行第1个字符
i = 0;
while(dis2[i] != '\0')
{
lcd_wdat(dis2[i]); //显示字符"二号电压"
i++;
}
lcd_pos(0x48); //设置显示位置为第二行第9个字符
i = 0;
while(dis2[i] != '\0')
{
lcd_wdat(dis2t[i]); //显示字符"二号时间"
i++;
}
lcd_pos(0x4b); //设置显示位置为第一行的第12个字符
lcd_wdat(0x30+0);
lcd_pos(0x4c); //设置显示位置为第一行的第12个字符
lcd_wdat(0x30+0);
lcd_pos(0x4d); //设置显示位置为第一行的第12个字符
lcd_wdat('.');
lcd_pos(0x4e); //设置显示位置为第一行的第12个字符
lcd_wdat(0x30+0);
//while(1);
lcd_pos(3); //设置显示位置为第一行的第12个字符
lcd_wdat(0x30+0);
lcd_pos(4); //设置显示位置为第一行的第12个字符
lcd_wdat('.');
lcd_pos(5); //设置显示位置为第一行的第12个字符
lcd_wdat(0x30+0);
while(1)
{
//if(ms>0) ISendByte(PCF8591,0x43);
if((count>0)&&(keyFlag == 1))
{
ISendByte(PCF8591,0x43);
Data=IRcvByte(PCF8591);
ss=Data*48/255;
a = ss/10 ;
b = (ss)%10;
//c = (ss-a*100-b*10)%10;
lcd_pos(3); //设置显示位置为第一行的第12个字符
lcd_wdat('0'+a);
lcd_pos(4); //设置显示位置为第一行的第12个字符
lcd_wdat('.');
lcd_pos(5); //设置显示位置为第一行的第12个字符
lcd_wdat(0x30+b);
//lcd_pos(6); //设置显示位置为第一行的第12个字符
//lcd_wdat(0x30+c);
shi=second/10;
ge=second%10;
lcd_pos(0x4b); //设置显示位置为第2行的第12个字符
lcd_wdat(0x30+shi);
lcd_pos(0x4c); //设置显示位置为第2行的第12个字符
lcd_wdat(0x30+ge);
lcd_pos(0x4d); //设置显示位置为第2行的第12个字符
lcd_wdat('.');
lcd_pos(0x4e); //设置显示位置为第2行的第12个字符
lcd_wdat(0x30+ms);
}
}
}
/*************************************
[ t1 (0.5ms)中断] 中断中做 PWM 输出
------------1000/(0.02ms*250)=200Hz
*************************************/
void T0zd(void) interrupt 1 //3 为定时器1的中断号 1 定时器0的中断号 0 外部中断1 2 外部中断2 4 串口中断
{
scan_key(); //检测按键
switch(key){
case 8:
{
keyFlag = 1;
TR0 = 0;
TH0 = 0xff;
TL0 = 0xf7;
TR0 = 1;
timer1++;
if(timer1>=100)
{
timer1=0;
ms++;
vt++;
}
if(timer1<=0) PWM=1;
else PWM=0;
if(ms == 10)
{
ms = 0;
count++;
if(count == 10)
{
count = 0;
second++;
if(second == 60)
{
second = 0;
}
}}
else
{
}
}break;
default:;
}
}
void T1zd(void) interrupt 3 //3 为定时器1的中断号 1 定时器0的中断号 0 外部中断1 2 外部中断2 4 串口中断
{
}
void scan_key() //按键检测函数
{
if(P1== 0xfe)
key= 1;
if(P1== 0xfd)
key= 2;
if(P1== 0xfb)
key= 3;
if(P1== 0xf7)
key= 4;
if(P1== 0xef)
key= 5;
if(P1== 0xdf)
key= 6;
if(P1== 0xbf)
key= 7;
if(P1== 0x7f)
key= 8;
}
</div>
复制代码
I2C.c
<div><font size="2">
/*************************此部分为I2C总线的驱动程序*************************************/
#include<reg52.h>
#include <intrins.h>
#include <I2C.H>
#define NOP() _nop_() /* 定义空指令 */
#define _Nop() _nop_() /*定义空指令*/
sbit SCL=P2^1; //I2C 时钟
sbit SDA=P2^0; //I2C 数据
bit ack; /*应答标志位*/
/*******************************************************************
起动总线函数
函数原型: void Start_I2c();
功能: 启动I2C总线,即发送I2C起始条件.
********************************************************************/
void Start_I2c()
{
SDA=1; /*发送起始条件的数据信号*/
_Nop();
SCL=1;
_Nop(); /*起始条件建立时间大于4.7us,延时*/
_Nop();
_Nop();
_Nop();
_Nop();
SDA=0; /*发送起始信号*/
_Nop(); /* 起始条件锁定时间大于4μs*/
_Nop();
_Nop();
_Nop();
_Nop();
SCL=0; /*钳住I2C总线,准备发送或接收数据 */
_Nop();
_Nop();
}
/*******************************************************************
结束总线函数
函数原型: void Stop_I2c();
功能: 结束I2C总线,即发送I2C结束条件.
********************************************************************/
void Stop_I2c()
{
SDA=0; /*发送结束条件的数据信号*/
_Nop(); /*发送结束条件的时钟信号*/
SCL=1; /*结束条件建立时间大于4μs*/
_Nop();
_Nop();
_Nop();
_Nop();
_Nop();
SDA=1; /*发送I2C总线结束信号*/
_Nop();
_Nop();
_Nop();
_Nop();
}
/*******************************************************************
字节数据发送函数
函数原型: void SendByte(UCHAR c);
功能: 将数据c发送出去,可以是地址,也可以是数据,发完后等待应答,并对
此状态位进行操作.(不应答或非应答都使ack=0)
发送数据正常,ack=1; ack=0表示被控器无应答或损坏。
********************************************************************/
void SendByte(unsigned char c)
{
unsigned char BitCnt;
for(BitCnt=0;BitCnt<8;BitCnt++) /*要传送的数据长度为8位*/
{
if((c<<BitCnt)&0x80)SDA=1; /*判断发送位*/
else SDA=0;
_Nop();
SCL=1; /*置时钟线为高,通知被控器开始接收数据位*/
_Nop();
_Nop(); /*保证时钟高电平周期大于4μs*/
_Nop();
_Nop();
_Nop();
SCL=0;
}
_Nop();
_Nop();
SDA=1; /*8位发送完后释放数据线,准备接收应答位*/
_Nop();
_Nop();
SCL=1;
_Nop();
_Nop();
_Nop();
if(SDA==1)ack=0;
else ack=1; /*判断是否接收到应答信号*/
SCL=0;
_Nop();
_Nop();
}
/*******************************************************************
字节数据接收函数
函数原型: UCHAR RcvByte();
功能: 用来接收从器件传来的数据,并判断总线错误(不发应答信号),
发完后请用应答函数应答从机。
********************************************************************/
unsigned char RcvByte()
{
unsigned char retc;
unsigned char BitCnt;
retc=0;
SDA=1; /*置数据线为输入方式*/
for(BitCnt=0;BitCnt<8;BitCnt++)
{
_Nop();
SCL=0; /*置时钟线为低,准备接收数据位*/
_Nop();
_Nop(); /*时钟低电平周期大于4.7μs*/
_Nop();
_Nop();
_Nop();
SCL=1; /*置时钟线为高使数据线上数据有效*/
_Nop();
_Nop();
retc=retc<<1;
if(SDA==1)retc=retc+1; /*读数据位,接收的数据位放入retc中 */
_Nop();
_Nop();
}
SCL=0;
_Nop();
_Nop();
return(retc);
}
/********************************************************************
应答子函数
函数原型: void Ack_I2c(bit a);
功能: 主控器进行应答信号(可以是应答或非应答信号,由位参数a决定)
********************************************************************/
void Ack_I2c(bit a)
{
if(a==0)SDA=0; /*在此发出应答或非应答信号 */
else SDA=1;
_Nop();
_Nop();
_Nop();
SCL=1;
_Nop();
_Nop(); /*时钟低电平周期大于4μs*/
_Nop();
_Nop();
_Nop();
SCL=0; /*清时钟线,钳住I2C总线以便继续接收*/
_Nop();
_Nop();
}</font>
</div>
复制代码
作者:
kean
时间:
2018-12-17 16:30
补充一点:PWM输出的电压值通过电压表测过啦,是没有问题的。
欢迎光临 (http://www.51hei.com/bbs/)
Powered by Discuz! X3.1