我们基于一个极为相似的官方工程,三下五除二改一下
下面代码是main函数代码部分。
视频效果:
使用金沙滩51单片机实现——用AD测量DA,按键可以调整DA值,AD测量到模拟量后液晶显示模拟量
如果需要完整工程代码或者技术支持可以加入我的嵌入式单片机交流QQ群:
471882291
main.c:
#include <reg52.h>
sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;
sbit KEY1 = P2^4;
sbit KEY2 = P2^5;
sbit KEY3 = P2^6;
sbit KEY4 = P2^7;
sbit KEY_OUT_4 = P2^0;
bit flag300ms = 1; //300ms定时标志
unsigned char T0RH = 0; //T0重载值的高字节
unsigned char T0RL = 0; //T0重载值的低字节
unsigned char code LedChar[] = { //数码管显示字符转换表
0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,
0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E
};
unsigned char LedBuff[6] = { //数码管显示缓冲区,初值0xFF确保启动时都不亮
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
int keynum=0,mode=0;
void ConfigTimer0(unsigned int ms);
unsigned char GetADCValue(unsigned char chn);
extern void I2CStart();
extern void I2CStop();
extern unsigned char I2CReadACK();
extern unsigned char I2CReadNAK();
extern bit I2CWrite(unsigned char dat);
extern void InitLcd1602();
extern void LcdShowStr(unsigned char x, unsigned char y, unsigned char *str);
extern void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int number,unsigned char length);
void Delay_ms(int ms) //@11.0592MHz
{
unsigned char i;
while(ms--)
{
for(i=0;i<113;i++);
}
}
/* 设置DAC输出值,val-设定值 */
void SetDACOut(unsigned char val)
{
I2CStart();
if (!I2CWrite(0x48<<1)) //寻址PCF8591,如未应答,则停止操作并返回
{
I2CStop();
return;
}
I2CWrite(0x40); //写入控制字节
I2CWrite(val); //写入DA值
I2CStop();
}
/* 按键驱动函数,检测按键动作,调度相应动作函数,需在主循环中调用 */
unsigned char Key_GetNum(void)
{
unsigned char KeyNum = 0; //定义变量,默认键码值为0
if(KEY1==0)
{
Delay_ms(18);
while (KEY1==0); //等待按键松手
Delay_ms(18);
KeyNum = 1;
}
if(KEY2==0)
{
Delay_ms(18);
while (KEY2==0); //等待按键松手
Delay_ms(18);
KeyNum = 2;
}
if(KEY3==0)
{
Delay_ms(18);
while (KEY3==0); //等待按键松手
Delay_ms(18);
KeyNum = 3;
}
if(KEY4==0)
{
Delay_ms(18);
while (KEY4==0); //等待按键松手
Delay_ms(18);
KeyNum = 4;
}
return KeyNum; //返回键码值,如果没有按键按下,所有if都不成立,则键码为默认值0
}
void main()
{
unsigned char val;
EA = 1; //开总中断
ENLED = 0; //使能U3,选择控制数码管
//ADDR3 = 1; //因为需要动态改变ADDR0-2的值,所以0-2不需要初始化了
ConfigTimer0(2); //配置T0定时2ms
InitLcd1602();
KEY_OUT_4=0;
while (1)
{
keynum=Key_GetNum( );
if (flag300ms)
{
flag300ms = 0;
//显示通道0的电压
val = GetADCValue(0); //获取ADC通道0的转换值
val = (val*25) / 255; //电压值=转换结果*2.5V/255,式中的25隐含了一位十进制小数
LCD_ShowNum(1, 1, val,6);
}
if(keynum==2)
{
mode+=50;
}
SetDACOut(mode);
}
}
/* 读取当前的ADC转换值,chn-ADC通道号0~3 */
unsigned char GetADCValue(unsigned char chn)
{
unsigned char val;
I2CStart();
if (!I2CWrite(0x48<<1)) //寻址PCF8591,如未应答,则停止操作并返回0
{
I2CStop();
return 0;
}
I2CWrite(0x40|chn); //写入控制字节,选择转换通道
I2CStart();
I2CWrite((0x48<<1)|0x01); //寻址PCF8591,指定后续为读操作
I2CReadACK(); //先空读一个字节,提供采样转换时间
val = I2CReadNAK(); //读取刚刚转换完的值
I2CStop();
return val;
}
/* 配置并启动T0,ms-T0定时时间 */
void ConfigTimer0(unsigned int ms)
{
unsigned long tmp; //临时变量
tmp = 11059200 / 12; //定时器计数频率
tmp = (tmp * ms) / 1000; //计算所需的计数值
tmp = 65536 - tmp; //计算定时器重载值
tmp = tmp + 12; //补偿中断响应延时造成的误差
T0RH = (unsigned char)(tmp>>8); //定时器重载值拆分为高低字节
T0RL = (unsigned char)tmp;
TMOD &= 0xF0; //清零T0的控制位
TMOD |= 0x01; //配置T0为模式1
TH0 = T0RH; //加载T0重载值
TL0 = T0RL;
ET0 = 1; //使能T0中断
TR0 = 1; //启动T0
}
/* T0中断服务函数,执行数码管动态显示、300ms定时 */
void InterruptTimer0() interrupt 1
{
static unsigned char i = 0; //动态扫描的索引
static unsigned char tmr300ms = 0; //300ms软件定时计数器
TH0 = T0RH; //重新加载重载值
TL0 = T0RL;
tmr300ms++;
if (tmr300ms >= 150) //定时300ms
{
tmr300ms = 0;
flag300ms = 1;
}
}