数模A/D和模数D/A转换的基本应用(下)

代码相关:

/**********Lcd1602.c**************/

#include < reg52.h >

#define LCD1602_DB P2

sbit LCD1602_RS = P0^3;

sbit LCD1602_RW = P0^2;

sbit LCD1602_E = P0^1;

void LcdWaitReady()

{

unsigned char sta;

LCD1602_DB = 0xFF;

LCD1602_RS = 0;

LCD1602_RW = 1;

do {

LCD1602_E = 1;

sta = LCD1602_DB; //读取状态字

LCD1602_E = 0;

} while (sta & 0x80); //bit7等于1表示液晶正忙,重复检测直到其等于0为止

}

/* 向LCD1602液晶写入一字节命令,cmd-待写入命令值 */

void LcdWriteCmd(unsigned char cmd)

{

LcdWaitReady();

LCD1602_RS = 0;

LCD1602_RW = 0;

LCD1602_DB = cmd;

LCD1602_E = 1;

LCD1602_E = 0;

}

/* 向LCD1602液晶写入一字节数据,dat-待写入数据值 */

void LcdWriteDat(unsigned char dat)

{

LcdWaitReady();

LCD1602_RS = 1;

LCD1602_RW = 0;

LCD1602_DB = dat;

LCD1602_E = 1;

LCD1602_E = 0;

}

void LcdSetCursor(unsigned char x, unsigned char y)

{

unsigned char addr;

if (y == 0) //由输入的屏幕坐标计算显示RAM的地址

addr = 0x00 + x; //第一行字符地址从0x00起始

else

addr = 0x40 + x; //第二行字符地址从0x40起始

LcdWriteCmd(addr | 0x80); //设置RAM地址

}

void LcdShowStr(unsigned char x, unsigned char y, unsigned char *str)

{

LcdSetCursor(x, y); //设置起始地址

while (*str != ‘�’) //连续写入字符串数据,直到检测到结束符

{

LcdWriteDat(*str++);

}

}

/* 初始化1602液晶 */

void InitLcd1602()

{

LcdWriteCmd(0x38);

LcdWriteCmd(0x0C);

LcdWriteCmd(0x06);

LcdWriteCmd(0x01);

}

/*********************IIC*******************/

#include < reg52.h >

#include < intrins.h >

#define Delay() {_nop_();_nop_();_nop_();_nop_();_nop_();}

sbit I2C_SCL = P3^7;

sbit I2C_SDA = P3^6;

/* 起始信号 */

void I2CStart()

{

I2C_SDA = 1;

I2C_SCL = 1;

Delay();

I2C_SDA = 0;

Delay();

I2C_SCL = 0;

}

/* 停止信号 */

void I2CStop()

{

I2C_SCL = 0; //首先确保SDA、SCL都是低电平

I2C_SDA = 0;

Delay();

I2C_SCL = 1; //先拉高SCL

Delay();

I2C_SDA = 1; //再拉高SDA

Delay();

}

/* I2C总线写操作,dat-待写入字节,返回值-从机应答位的值 */

bit I2CWrite(unsigned char dat)

{

bit ack;

unsigned char BitCnt;

for (BitCnt=0x80; BitCnt!=0; BitCnt > >=1)

{

if ((BitCnt&dat) == 0)

I2C_SDA = 0;

else

I2C_SDA = 1;

Delay();

I2C_SCL = 1; //拉高SCL

Delay();

I2C_SCL = 0; //再拉低SCL,完成一个位周期

}

I2C_SDA = 1;

Delay();

I2C_SCL = 1;

ack = I2C_SDA;

Delay();

I2C_SCL = 0;

return (ack);

}

/* I2C总线读操作,并发送应答信号或者非应答信号,如果cnt为1则发送应答信号,

如果cnt为非1的值则发送非应答信号,返回值-读到的字节 */

unsigned char I2CReadACKORNOT(bit cnt)

{

unsigned char BitCnt;

unsigned char dat;

I2C_SDA = 1; //首先确保主机释放SDA

for (BitCnt=0x80; BitCnt!=0; BitCnt > >=1) //从高位到低位依次进行

{

Delay();

I2C_SCL = 1; //拉高SCL

if(I2C_SDA == 0) //读取SDA的值

dat &= ~BitCnt; //为0时,dat中对应位清零

else

dat |= BitCnt; //为1时,dat中对应位置1

Delay();

I2C_SCL = 0; //再拉低SCL,以使从机发送出下一位

}

if(cnt)

I2C_SDA = 0; //8位数据发送完后,拉低SDA,发送应答信号

else

I2C_SDA = 1;

Delay();

I2C_SCL = 1; //拉高SCL

Delay();

I2C_SCL = 0; //再拉低SCL完成应答位,并保持住总线

return dat;

}

/******************main.c*************************/

#include < reg52.h >

bit flags = 1;

unsigned char GetValue(unsigned char chn);

void NumToString(unsigned char *str, unsigned char val);

extern void I2CStart();

extern void I2CStop();

unsigned char I2CReadACKORNOT(bit cnt);

extern bit I2CWrite(unsigned char dat);

extern void InitLcd1602();

extern void LcdShowStr(unsigned char x, unsigned char y, unsigned char *str);

void main()

{

unsigned char val;

unsigned char str[10];

EA = 1; //开总中断

TMOD &= 0xF0; //清零T0的控制位

TMOD |= 0x01; //配置T0为模式1

TH0 = (65536-9216)/256; //加载T0重载值,定时10ms

TL0 = (65536-9216)%256;

ET0 = 1; //使能T0中断

TR0 = 1; //启动T0

InitLcd1602(); //初始化液晶

LcdShowStr(0, 0, “AN0: AN1: AN3:”); //显示通道指示

while (1)

{

if (flags)

{

flags = 0;

//显示通道0的电压

val = GetValue(0); //获取ADC通道0的转换值

NumToString(str, val); //转为字符串格式的电压值

LcdShowStr(0, 1, str); //显示到液晶上

//显示通道1的电压

val = GetValue(1);

NumToString(str, val);

LcdShowStr(6, 1, str);

//显示通道3的电压

val = GetValue(3);

NumToString(str, val);

LcdShowStr(12, 1, str);

}

}

}

unsigned char GetValue(unsigned char chn)

{

unsigned char val;

I2CStart();

if(I2CWrite(0x48< < 1))

{

I2CStop();

return 0;

}

I2CWrite(0x40 | chn);

I2CStart();

I2CWrite(0x48< < 1 | 0x01);

I2CReadACKORNOT(1);

val = I2CReadACKORNOT(0);

I2CStop();

return val;

}

void NumToString(unsigned char *str, unsigned char val)

{

val = (val*50)/255;

str[0] = (val/10) + ‘0’;

str[1] = ‘.’;

str[2] = (val%10) + ‘0’;

str[3] = ‘�’;

}

/* T0中断服务函数 */

void InterruptTimer0() interrupt 1

{

static unsigned char tm100ms = 0;

TH0 = (65536-9216)/256; //加载T0重载值

TL0 = (65536-9216)%256;

tm100ms++;

if (tm100ms >= 10) //定时100ms

{

tm100ms = 0;

flags = 1;

}

}

AN3通道测得实际电压变化,通过滑动变阻器可以改变相应的值;AN0通道测得光敏电阻的阻值;AN1测得热敏电阻的相应阻值,需要货源才会变化值。