yzex86 2023-06-22 16:24 采纳率: 66.7%
浏览 38

C51编程DAC波形无法输出

C51使用DAC0832无法输出波形
可能是写输出函数有问题,本人用的是P0锁存加定时器
具体的输出函数在case3后面,前面可以忽略
附上程序框图

img


原理图

img


#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花括号

}//第一级大循环花括号
}//主函数花括号
  • 写回答

1条回答 默认 最新

  • 泡沫o0 2023年度博客之星上海赛道TOP 1 2023-06-24 12:18
    关注

    @ada;
    回答一下

    评论

报告相同问题?

问题事件

  • 创建了问题 6月22日

悬赏问题

  • ¥15 CPU卡指令整合指令数据都在图片上
  • ¥15 火车票关联12306问题
  • ¥15 odoo17处理受托加工产品
  • ¥15 如何用MATLAB编码图三的积分
  • ¥15 圆孔衍射光强随孔径变化
  • ¥15 MacBook pro m3max上用vscode运行c语言没有反应
  • ¥15 ESP-PROG配置错误,ALL ONES
  • ¥15 结构功能耦合指标计算
  • ¥50 AI大模型精调(百度千帆、飞浆)
  • ¥15 非科班怎么跑代码?如何导数据和调参