C51使用DAC0832无法输出波形
可能是写输出函数有问题,本人用的是P0锁存加定时器
具体的输出函数在case3后面,前面可以忽略
附上程序框图
原理图
#include <reg52.h>
#include <stdio.h>
#include <intrins.h>
#define BaudRate 9600//波特率为9600
#define LcdData P0//定义lcd端口——p0
#define uchar unsigned char
#define uint unsigned int//定义简写形式
sbit LS373_LE=P3^6;//定义led灯口变量
sbit KEY_INT=P3^2;//INT0的引脚
sbit KEY_LINE0=P2^6;
sbit KEY_LINE1=P2^5;
sbit KEY_LINE2=P2^4;//第一行,第二行和第三行
sbit ILE_DAC=P2^7;
sbit CS1=P1^7;
sbit CS2=P1^6;
sbit CS3=P1^5;
sbit CS4=P1^4;//接7端数码管的下端
sbit RS=P1^2; //并行的指令/数据选择信号, H数据, L命令
sbit RW=P1^1; //并行读写选择信号, H读, L写
sbit EN=P1^0; //并行使能端, H有效, L无效
bit FlagKeyChecked;//按键是否被按下
unsigned char FREQ=250;//函数的初始周期为250ms
unsigned char NUM=0;//256位,不需要再置零
unsigned char LedVal;
unsigned char LedsVal=0xFE;//11111110
unsigned int IntervalLedsChange=500;//led的初始点亮时间为500ms
unsigned char T0_High;
unsigned char T0_Low;//定义THO和TLO
int Cnt1ms;//计数变量
int Cntlms1;
int Cnt1ms7Seg;//七段数码管的值
bit FlagLedsChange=0;
bit FlagUartSend=0;//uart发送标志
bit FlagKeyPressing=0;//INT0中断标志变量
bit FlagKeyPressed=0;//INT0
bit FlagDAC=0;
unsigned char QianWei;
unsigned char BaiWei;
unsigned char ShiWei;
unsigned char GeWei;//定义数码管的四位数字变量
unsigned int DispVal7Seg;
unsigned char mod2;
unsigned char mod3;//处理选择功能后的按键e
char ZhongJianzhi;//用于实验三功能二的中间变量
long HZ=11059200L;//频率为11.0592MHZ
unsigned char code SegCode[]={0x03,0x9F,0x25,0x0D,0x99,0x49,0x41,0x1F,0x01,0x09};//七段数码管0-9
unsigned int receive_i=0;//串口接收计数变量
unsigned char receive_number[16]={'\0'};//串口接收存储数组
bit Flag1sOK;//定时器中断标志变量
uchar code sin_tab[256] = //正弦波输出表
{
0x7F,0x82,0x85,0x88,0x8B,0x8F,0x92,0x95,0x98,0x9B,0x9E,0xA1,0xA4,0xA7,0xAA,0xAD
,0xB0,0xB3,0xB6,0xB8,0xBB,0xBE,0xC1,0xC3,0xC6,0xC8,0xCB,0xCD,0xD0,0xD2,0xD5,0xD7
,0xD9,0xDB,0xDD,0xE0,0xE2,0xE4,0xE5,0xE7,0xE9,0xEB,0xEC,0xEE,0xEF,0xF1,0xF2,0xF4
,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFB,0xFC,0xFD,0xFD,0xFE,0xFE,0xFE,0xFE,0xFE
,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFD,0xFD,0xFC,0xFB,0xFB,0xFA,0xF9,0xF8,0xF7,0xF6
,0xF5,0xF4,0xF2,0xF1,0xEF,0xEE,0xEC,0xEB,0xE9,0xE7,0xE5,0xE4,0xE2,0xE0,0xDD,0xDB
,0xD9,0xD7,0xD5,0xD2,0xD0,0xCD,0xCB,0xC8,0xC6,0xC3,0xC1,0xBE,0xBB,0xB8,0xB6,0xB3
,0xB0,0xAD,0xAA,0xA7,0xA4,0xA1,0x9E,0x9B,0x98,0x95,0x92,0x8F,0x8B,0x88,0x85,0x82
,0x7F,0x7C,0x79,0x76,0x73,0x6F,0x6C,0x69,0x66,0x63,0x60,0x5D,0x5A,0x57,0x54,0x51
,0x4E,0x4B,0x48,0x46,0x43,0x40,0x3D,0x3B,0x38,0x36,0x33,0x31,0x2E,0x2C,0x29,0x27
,0x25,0x23,0x21,0x1E,0x1C,0x1A,0x19,0x17,0x15,0x13,0x12,0x10,0x0F,0x0D,0x0C,0x0A
,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x03,0x02,0x01,0x01,0x00,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x02,0x03,0x03,0x04,0x05,0x06,0x07,0x08
,0x09,0x0A,0x0C,0x0D,0x0F,0x10,0x12,0x13,0x15,0x17,0x19,0x1A,0x1C,0x1E,0x21,0x23
,0x25,0x27,0x29,0x2C,0x2E,0x31,0x33,0x36,0x38,0x3B,0x3D,0x40,0x43,0x46,0x48,0x4B
,0x4E,0x51,0x54,0x57,0x5A,0x5D,0x60,0x63,0x66,0x69,0x6C,0x6F,0x73,0x76,0x79,0x7C
};
char code KeyCode[3][4]= //定义按键数组
{
{'1','2','3','4'},
{'5','6','7','8'},
{'9','0','*','#'}
};
unsigned char ScanMatrixKeys(void)//逐行扫描函数
{
static unsigned char CurScanLine=0;//扫描行
unsigned char Val_Column;
unsigned char j;
unsigned char ret;
bit FlagKeyChecked1;
ret = 0;
P2 |= 0x7F; //P2.0~P2.6 = 1; 行和列全部置1
switch (CurScanLine)
{
case 0:
KEY_LINE0 = 0; //LINE0 = 0; //当前扫描行输出0
break;
case 1:
KEY_LINE1 = 0; //LINE1 = 0;
break;
case 2:
KEY_LINE2 = 0; //LINE2 = 0;
break;
}
FlagKeyChecked1 = 0;
Val_Column = P2; //读列值
Val_Column &= 0x0F; //保留低4位列值
if(Val_Column != 0x0F)
{
for(j=0;j<4;j++)
{
if((Val_Column & (1<<(3-j))) == 0x00) //找出为0的列
{
ret = KeyCode[CurScanLine][j]; //保存键码
FlagKeyChecked1 = 1;
break;
}
}
if(FlagKeyChecked1)
{
do
{
P2 |= 0x0F; //列线都置1
Val_Column = P2; //读列值
Val_Column &= 0x0F; //保留低4位列值
}while(Val_Column != 0x0F); //等待按键释放
}
}
CurScanLine = (CurScanLine+1)%3; //0 1 2
return ret;
}
void LedChange(unsigned char val)//控制led的改变函数
{
unsigned char temp1;
unsigned char temp2;
EA = 0;
temp1 = P0; //临时保存P0 P1的值
temp2 = P1;
P1 &= 0x0f; //close 7-seg LED
P0 = val;
LS373_LE = 1;
LS373_LE = 0; //led产生下降沿
P1 = temp2;
P0 = temp1; //恢复原值
EA = 1;
}
void DAC_Cntl(unsigned char val)
{
EA=0;
P0 = val;
ILE_DAC=1;
ILE_DAC=0;
EA = 1;
}
void EInt0_Init(void)//下降沿触发中断
{
EX0 = 1;
IT0 = 1;
}
void T0_Init(void)//TO的初始化
{
TMOD &= 0xF0;
TMOD |= 0x01; //T0 方式1
T0_High = (65536-1*HZ/12000)/256;
T0_Low = (65536-1*HZ/12000)&0xFF; //1ms定时
TH0 = T0_High;
TL0 = T0_Low;
ET0 = 1; //使能T0中断
TR0 = 1;
}
unsigned char Lcd_CheckBusy(void)
{
unsigned char Busy;
LcdData=0xff;
RS=0;
RW=1;
EN=1;
_nop_();
Busy=LcdData&0x80;
EN=0;
return Busy;
}
void Lcd_WriteData(unsigned char Data)
{
while(Lcd_CheckBusy());
RS=1;
RW=0;
EN=0;
_nop_();
_nop_();
LcdData=Data;
EN=1;
_nop_();
_nop_();
EN=0;
}
void Lcd_WriteCmd(unsigned char CmdCode)
{
while(Lcd_CheckBusy());
RS=0;
RW=0;
EN=0;
_nop_();
_nop_();
LcdData=CmdCode;
_nop_();
_nop_();
EN=1;
_nop_();
_nop_();
EN=0;
}
void Lcd_Init()//lcd的初始化
{
Lcd_WriteCmd(0x30); //选择基本指令集
Lcd_WriteCmd(0x0c); //开显示,光标关,闪烁关
Lcd_WriteCmd(0x01); //清除显示,并且设定地址指针为00H
Lcd_WriteCmd(0x06); //指定在资料的读取及写入时,设定游标的移动方向及指定显示的移位
}
void Lcd_Clear(unsigned char Mode)
{
unsigned char x,y,ii;
unsigned char Temp;
if(Mode%2==0)
Temp=0x00;
else
Temp=0xff;
Lcd_WriteCmd(0x36);//扩充指令 绘图显示
for(ii=0;ii<9;ii+=8)
for(y=0;y<0x20;y++)
for(x=0;x<8;x++)
{
EA=0;
Lcd_WriteCmd(y+0x80); //行地址
Lcd_WriteCmd(x+0x80+ii); //列地址
Lcd_WriteData(Temp); //写数据 D15-D8
Lcd_WriteData(Temp); //写数据 D7-D0
EA=1;
}
Lcd_WriteCmd(0x30);
}
void Send_Byte(unsigned char val)//发送函数,到串口
{
SBUF = val;
while(!TI);//等待发送完成
TI = 0; //发送完成后清零发送标志位
}
void Send_Bytes(unsigned char *pbuf ,int size)//发送到串口
{
int i;
for(i=0;i<size;i++)
{
Send_Byte(pbuf[i]);
}
}
void Uart_ISR(void) interrupt 4 //串口接收中断
{
if(RI)
{
RI=0;
if(receive_i<=15)
receive_number[receive_i++]=SBUF;
}
}
void Uart_Init(void)//uart的初始化
{
SCON = 0x50; //Mode = 1 ren = 1
TMOD |= 0x20; //T1 方式2
PCON &= 0x7F;
TH1 = 256-11059200/32/12/9600;
ES = 1;
TR1 = 1;
}
void Init_gVars(void)//数码管的初始化
{
Cnt1ms = 0;
Flag1sOK = 0;
LedVal = 0;
Cnt1ms7Seg = 0;
IntervalLedsChange = 500;
DispVal7Seg = IntervalLedsChange;
QianWei = DispVal7Seg/1000;
BaiWei = DispVal7Seg%1000/100;
ShiWei = DispVal7Seg%100/10;
GeWei = DispVal7Seg%10;
}
void T0_Isr(void) interrupt 1//TO的中断
{
static unsigned char CntKeyJitter=0; //注意static的用法
static unsigned char CurScanCs=0;
TF0 = 0;//终端溢出标志清零
if(++Cnt1ms >= DispVal7Seg) //1s is ok;
{
Cnt1ms = 0;
Flag1sOK = 1;
}
if(++Cntlms1>=1)//250*1ms=250ms=4HZ
{
Cntlms1=0;
FlagDAC = 1;
}
if(FlagKeyPressing) //貌似INT0键被按下,检查INT0是否真的被按下
{
if(++CntKeyJitter >= 40) //延时20ms后再读按键,如为零则真有键被按下,否则是抖动
{
CntKeyJitter = 0;
if(KEY_INT == 0) //读INT0引脚,为0:键正被按下...
FlagKeyPressed = 1;
else //读INT0引脚,为1:无键按下
FlagKeyPressed = 0;
FlagKeyPressing = 0;
}
}
if(++Cnt1ms7Seg >= 5) //50Hz Scan 7SEG
{
Cnt1ms7Seg = 0;
P1 &= 0x0f; //CS1-4 = 0 //场消隐
switch (CurScanCs)
{
case 0x00:
P0 = SegCode[QianWei];
CS4 = 1;
break;
case 0x01:
P0 = SegCode[BaiWei];//显示具体数字
CS3 = 1;
break;
case 0x02:
P0 = SegCode[ShiWei];
CS2 = 1;
break;
case 0x03:
P0 = SegCode[GeWei];
CS1 = 1;
break;
}
CurScanCs = (CurScanCs+1)%4; //0 1 2 3 0 1 2 3;
}
TH0 = T0_High; //重新重装T0初值
TL0 = T0_Low;
}
void EInt0_Isr(void) interrupt 0
{
FlagKeyPressing = 1; //貌似INT0键被按下...
}
void update_tube(int newval)
{
unsigned int val;
val = newval;
QianWei = val/1000;
BaiWei = val%1000/100;
ShiWei = val%100/10;
GeWei = val%10;
}
void Lcd_WriteStr(unsigned char x,unsigned char y,unsigned char *Str)
{
if((y>3)||(x>7))
return;//如果指定位置不在显示区域内,则不做任何写入直接返回
EA=0;
switch(y)
{
case 0:
Lcd_WriteCmd(0x80+x);
break;
case 1:
Lcd_WriteCmd(0x90+x);
break;
case 2:
Lcd_WriteCmd(0x88+x);
break;
case 3:
Lcd_WriteCmd(0x98+x);
break;
}
while(*Str>0)
{
Lcd_WriteData(*Str);
Str++;
}
EA=1;
}
void Tupian(unsigned char*tu)
{
unsigned char i;
unsigned char j;
Lcd_WriteCmd(0x34); //打开扩充指令动作
for(i=0;i<32;i++)
{Lcd_WriteCmd(0x80+i); //上半屏写入行地址
Lcd_WriteCmd(0x80); //列
for(j=0;j<16;j++)
Lcd_WriteData(*tu++);}
for(i=0;i<32;i++)
{Lcd_WriteCmd(0x80+i); //上半屏写入行地址
Lcd_WriteCmd(0x88); //列,地址改变
for(j=0;j<16;j++)
Lcd_WriteData(*tu++);}
Lcd_WriteCmd(0x36);
Lcd_WriteCmd(0x30);
}
void Uart_Send()
{
Lcd_Init();//lcd的初始化
Lcd_Clear(0);
Lcd_WriteStr(0,0,"1.串口发送测试");
while(1)
{
mod2 = ScanMatrixKeys();
if(mod2!=0xFF)
{
Send_Byte(mod2);
}
}
}
void Uart_Receive()
{
unsigned char j=0;
while(1)
{
if(receive_number[0]!='\0')
{
Lcd_Init();
Lcd_Clear(0);
Lcd_WriteStr(0,1,receive_number);
for(j=0;j<=15;j++)
{
receive_number[j]='\0';}
receive_i=0;
}
}
}
void Lcd_Receive(void)
{
unsigned char code Seg_lcd1[]={"在调试助手上发送"};
unsigned char code Seg_lcd2[]={"接收到的字符串是"};
Lcd_Init();//lcd的初始化
Lcd_Clear(0);
Lcd_WriteStr(0,0,Seg_lcd1);
Lcd_WriteStr(0,1,Seg_lcd2);
Lcd_WriteStr(0,2,receive_number);
}
void main(void)
{
T0_Init();//定时器0:1ms定时,中断方式处理溢出
Uart_Init();//uart的初始化
EInt0_Init(); //下降沿触发中断,INT0的初始化
Init_gVars();//数码管的初始化
Lcd_Init();//lcd的初始化
Lcd_Clear(0);
Lcd_WriteStr(0,0,"1.流水灯测试");
Lcd_WriteStr(0,1,"2.串口功能测试");
Lcd_WriteStr(0,2,"3.D/A Work test");
Lcd_WriteStr(0,3,"");
TI = 1;
EA=1;//开启总中断允许开关
while(1)
{
unsigned char CurKey;
CurKey = ScanMatrixKeys();
if(Flag1sOK)//如果Flag1sOK为1
{
Flag1sOK = 0;
LedChange( LedsVal);//11111110
LedsVal = ~ LedsVal;//00000001
LedsVal = LedsVal<<1;//00000010
LedsVal = ~ LedsVal; //11111101
if(LedsVal==0xFF)
{
LedsVal =0xFE;
}
}//跑马灯实现
if(FlagKeyPressed) //有INT0按键按下了吗?
{
FlagKeyPressed = 0;
FlagKeyPressing = 0;
FlagUartSend = 1; //置串口需要发出标志
DispVal7Seg = DispVal7Seg-10;
update_tube(DispVal7Seg);
if(DispVal7Seg <= 0)//判断是否小于500ms
{DispVal7Seg = 500;
update_tube(500);}
}
if(FlagUartSend) //需要发送数据至串口吗?
{
FlagUartSend = 0;
Send_Bytes((unsigned char *)&IntervalLedsChange,sizeof(DispVal7Seg)); //注意字节顺序
}
if(CurKey!=0xFF)
{
switch(CurKey)
{
case '1':
{
Lcd_Init();
Lcd_Clear(0);
Lcd_WriteStr(0,0,"1.流水灯测试");
}
break;
case '2':
{//串口测试功能测试子菜单
Lcd_Init();
Lcd_Clear(0);//清屏
Lcd_WriteStr(0,0,"1.发送功能测试");
Lcd_WriteStr(0,1,"2.接收功能测试");
//如果按键按下了
//发送功能测试
while(1)
{
mod2 = ScanMatrixKeys();
if(mod2!=0xFF)
{
switch(mod2)//串口发送相应ASCII码值
{
case'1':
Uart_Send();
break;
case'2':
{
Lcd_Init();
Lcd_Receive();
Uart_Receive();
break;
}
break;
}
}
}
}
break;
case '3':
{
//数模转换功能子菜单,频率的改变可借助INT0键,显示频率借助数码管 Send_Bytes
Lcd_Init();
Lcd_Clear(0);//清屏
Lcd_WriteStr(0,0,"1.输出sin");
Lcd_WriteStr(0,1,"2.输出三角");
Lcd_WriteStr(0,2,"3.输出锯齿");
while(1)
{
mod3 = ScanMatrixKeys();
if(mod3!=0xFF)
{
switch(mod3)
{
case'1':
{
Lcd_Init();
Lcd_Clear(0);
Lcd_WriteStr(0,2,"输出sin");
while(1)
if(FlagDAC)//如果Flag1sOK为1
{
FlagDAC = 0;
DAC_Cntl(sin_tab[NUM++]);
if(NUM>=256)
NUM=0;
}
}
break;
case'2':
{
Lcd_Init();
Lcd_Clear(0);
Lcd_WriteStr(0,0,"输出三角波");
while(1)
{
if(FlagDAC)//如果Flag1sOK为1
{
FlagDAC=0;
if(NUM<=128)
{
DAC_Cntl(NUM);
NUM++;
}
if(NUM>129)
{
DAC_Cntl(256-NUM);
NUM++;
}
if(NUM>=256)
NUM=0;
}
}
}
break;
case'3':
{
Lcd_Init();
Lcd_Clear(0);
Lcd_WriteStr(0,1,"输出锯齿波");
while(1)
{
if(FlagDAC)//如果Flag1sOK为1
{
FlagDAC=0;
DAC_Cntl(NUM++);
if(NUM>=256)
NUM=0;
}
}
}
break;
}
}
}
break;
}//第一级case3花括号
}//switch花括号
}//第一级if花括号
}//第一级大循环花括号
}//主函数花括号