那篇是做的一次实验简单的仿真,不过被多次转载,还有其他系列的仿真和代码,下面放的这个是比较大的仿真,你看这是否达到贵站的要求?1.申请ID:xuanhu2.个人邮箱: 2720846128@qq.com3.原创文章:序列检测器文章链接:实验7-单片机AD和DA实验https://blog.csdn.net/qq_43353985/article/details/107964780?spm=1001.2014.3001.5502其他同系列文章:有仿真和完整的代码(原创)
  实验1-单片机流水灯控制实验  实验2-单片机数码管和按键实验  实验3-单片机定时器中断实验  实验4-单片机外部中断实验  实验5-单片机串行口中断实验  实验6-单片机扩展RAM6264实验  实验7-单片机AD和DA实验
STM32 LoRa无线数传模块 PC通过串口传输数据到单片机:
实验7-单片机AD和DA实验
  之前做的一次实验,51单片机AD和DA实验,数模使用芯片0832,模数转换使用0809。在做实验时曾经遇到一个问题,模数转换0809是不是只能输出0~ 5V,能不能输出-5V~5V的?当时在网上找了很多,没什么收获,在寻求帮助的过程中,一个朋友说可以,当时他分享了一个链接:http://m.elecfans.com/article/576838.html,看后明白解决方法是加一个反相器,最后把实验的要求圆满完成。如有问题欢迎指正。
实验目的:
  掌握数模和模数转换的原理;
  学会数模0832和模数0809的操作和使用。
实验内容:
  用单片机、数模0832、模数0809,可变电阻实现0 ~ 5v电压输出,或者选择电压调节器(如果有该器件),数模转换实验,将可变电阻分压后的电压值,应用数码管显示,保留小数点后2位。模数转换实验,输出的幅值0~5v的方波,三角波,锯齿波(-5V ~ 5V),应用示波器进行显示。
实验环境:
   MDK-ARM V5.21a、Proteus 8.6
Proteus原理图
   方波(out输出0~5V,out1输出-5 V ~5V,考虑到反相器,两个输出波形相位差180°):
   三角波(out输出0~5V,out1输出-5 V ~5V)
   锯齿波(out输出0~5V,out1输出-5 V ~5V)
   P34按下后,进入ADC转换,模拟电压量在数码管上显示。
主要元器件:
DEVICES说明
7SEG-MPX8-CC-BLUE八位共阴数码管
8255A可编程并行接口芯片
ADC0808模数转换芯片
DAC0832模数转换芯片
74HC573锁存器
74LS373锁存器
AT89C51MCU
BUTTON按键
CAP普通电容
CAP-ELEC电解电容
CRYSTAL晶振
RES电阻
RESPACK-8排阻
  51单片机的P0口做IO口使用时是漏极开路输出,其引脚一般需要在片外接一定阻值的上拉电阻,此时端口不存在高阻抗的悬浮状态,因此它是一个准双向口。同时,P0口每一位的驱动能力是P1~P3口的两倍,每位可以驱动8个LSTTL(Low-power Schottky TTL,即低功耗肖特基TTL)输入,89C51等单片机任何一个端口想要获得较大的驱动能力,必须采用低电平输出。
  时钟晶体振荡频率为f_{osc}=11.0592MHZfosc​=11.0592MHZ
  时钟周期相当于T_{osc}=\frac{1}{f_{osc}} \approx 90.42nsTosc​=fosc​1​≈90.42ns
  复位电路的话通过给89C51等单片机的复位引脚RST加上大于2个机器周期的高电平(即24个时钟振荡周期)就可以使单片机复位。
KEIL工程:
  1.DAC0832的输出电压Vo与输入数字量B的关系是(采用的基准电压为-5V):
V_o=-\frac{(B*V_{REF})} {256}Vo​=−256(B∗VREF​)​
  2.两路0~5V的被测电压分别加到ADC0809的IN0和IN1通道,进行A/D转换,两路输入电压的大小可通过手动调节RV1和RV2来实现。通过鼠标滚轮来放大虚拟电压表的图标,可清楚地看到输入电压的测量结果。
  3.ADC0809采用的基准电压为+5V,转换所得结果二进制数字addata所代表的电压的绝对值为addata5V/256,而若将其显示到小数点后两位,不考虑小数点的存在(将其乘以100),其计算的数值为: (addata 100/256)5V≈addata1.96 V。控制小数点显示在左边第2、6位数码管上,即为实际的测量电压。
  4.使用功能键(P3^4)选择工作模式:当为高电平时,为DAC工作模式,数字量转模拟量,在示波器显示;当为低电平时为ADC工作模式,模拟量转数字量,在数码管显示。目前,单片机开机后只能切换一次模式,再返回原来模式要重启,待改进。
  5.鉴于51单片机的端口可能不够,我采用了82C55芯片来进行端口扩展,设置PA口为输入,其他口(PB、PC高四位、PC低四位)全为输出。
  头文件以及宏定义等:
/*====================================================Program: 单片机模/数和数/模实验******Encoding: ANSITime: 2020/06/21Task: 选用单片机、数模0832、模数0809,可变电阻实现 0~5v电压输出,或者选择电压调节器(如果有该器 件)。 数模转换实验:将可变电阻分压后的电压值,应用 数码管显示,保留小数点后2位。 模数转换实验:输出的幅值0~5v的方波,三角波, 锯齿波(-5V~5V),应用示波器进行显示。Introduction:使用功能键(P3^4)选择工作模式: 当为高电平时,为DAC工作模式,数字量转模拟量, 在示波器显示-DAC;(注意要等示波器稳定后观察) 当为低电平时为ADC工作模式,模拟量转数字量, 在数码管显示-ADC。 目前,单片机开机后只能切换一次模式,再返回原 来模式要重启,待改进。=====================================================*/#include "reg52.h"#include "absacc.h" //定义地址所需的头文件#include <intrins.h> //有各种移位和NOP指令#include <math.h>#define PA8255 XBYTE[0xff7c] //0xff7c为82C55PA端口地址#define PB8255 XBYTE[0xff7d] //0xff7d为82C55PB端口地址#define PC8255 XBYTE[0xff7e] //0xff7e为82C55PC端口地址#define COM8255 XBYTE[0xff7f] //0xff7f为82C55控制寄存器地址#define DAC_PORT P2 //DAC0832连接端口#define K_SQU 1 // 方波标志#define K_TRI 2 //三角波标志#define K_SAW 3 //锯齿波标志typedef unsigned char u8;typedef unsigned int u16;typedef unsigned long u32;sbit rst_8255=P3^5; //82C55复位引脚sbit START = P1^4;//连了ADC0808的ALE(CBA编码的锁存信号)sbit OE = P1^3;sbit add_a = P1^2;sbit add_b = P1^1;sbit add_c = P1^0;sbit DAC_CS_WR=P3^0; //DAC0832使能口sbit K1=P3^1;sbit K2=P3^2;sbit K3=P3^3;sbit Func=P3^4;u8 code Duanma[={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};/*0123456789abcdef*/u8 code Weima[ ={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};/*自左向右*/u8 TempData[8; //全局显示变量u16 addata=0,addata1=0,i,adcflag=0,dacflag=0;//全局变量u8 mode; //模式:u16 freq; //频率u8 time; //计次参数u8 AM; //调幅
  主函数:
int main(void){ while(1) { while(Func==1) { if(dacflag==0) { DAC_Init(); dacflag=1; } scanKey();//数字量转模拟量,在示波器显示-DAC } while(Func==0) { if(adcflag==0) { ADC_Init(); adcflag=1; } Gain(); //模拟量转数字量,在数码管显示-ADC Display(0,8); } }}
  初始化及子函数:
void DAC_Init(){ time=0; DAC_CS_WR=0; DAC_PORT=0; mode=0; freq=100; //默认频率100Hz AM=255; //最大幅度 TMOD &= 0xF0; //设置定时器模式 TMOD |= 0x02; //设置定时器模式 TL0 = 0x9C; //设置定时初值 TH0 = 0x9C; TF0 = 0; //清除TF0标志 TR0 = 1; //定时器0开始计时 EA = 1; //开总中断 ET0 = 1; //开定时器0中断}void ADC_Init(void) { //EA = 0; //关闭定时器 rst_8255=1; //reset_8255 delayms(1); rst_8255=0; COM8255=0x90; //方式0,PA输入 PC高四位/PB/PC低四位全输出}void Timer0Work() interrupt 1 //中断服务函数{ switch(mode) { case K_SQU:squ_wave((u8)((time*freq/100)%100));break; //计算出波的位置 case K_TRI:tri_wave((u8)((time*freq/100)%100));break; case K_SAW:saw_wave((u8)((time*freq/100)%100));break; } time++; if(time>=100)//计数100次 time=0;}
  显示、数据处理函数等:
void Display(u8 FirstBit,u8 Num){ static u8 i=0; PB8255=0xff; //位码消隐 PC8255=0x00; //段码消隐 PB8255=Weima[i+FirstBit; //位码数据,从数码管从左到右的第一位开始对应 if(i==1||i==5) { PC8255=TempData[i+128; //段码数据 } else PC8255=TempData[i; //段码数据 //delayms(1); i++; if(i==Num) i=0;}void Gain(void){ START=0; add_a=0; //采集第一路信号 add_b=0; add_c=0; START=1; //根据时序图启动ADC0808的AD程序 START=0; OE=1; //转换结果允许输出 addata=PA8255; addata=addata*1.96; //根据AD原理将采得的二进制数转换成可读的电压 OE=0; START=0; add_a=1; //采集第二路信号 add_b=0; add_c=0; START=1; //根据时序图启动ADC0808的AD程序 START=0; OE=1; //转换结果允许输出 addata1=PA8255; addata1=addata1*1.96; //根据AD原理将采得的二进制数转换成可读的电压 OE=0; Display(0,8); //防止断帧 TempData[3=Duanma[addata%10; //显示到数码管上 TempData[2=Duanma[addata/10%10; TempData[1=Duanma[addata/100%10; TempData[0=Duanma[addata/1000; Display(0,8); //防止断帧 TempData[7=Duanma[addata1%10; //显示到数码管上 TempData[6=Duanma[addata1/10%10; TempData[5=Duanma[addata1/100%10; TempData[4=Duanma[addata1/1000; }void scanKey(void){ if(K1==0) { mode=1; } if(K2==0) { mode=2; } if(K3==0) { mode=3; }}void squ_wave(u8 location)//方波函数{ if(location<50){ DAC_PORT=AM; } else{ DAC_PORT=0x00; }}void tri_wave(u8 location)//三角波函数{ u8 y; if(location<50) y=(50-location)*AM/50; else y=(location-50)*AM/50; DAC_PORT=y;}void saw_wave(u8 location)//锯形波函数{ DAC_PORT=location*AM/100;}void delayms(u16 j){ u8 i; for(;j>0;j--) { i=250; while(--i); i=249; while(--i); }}
参考文献
1.《单片机原理与接口技术》张毅刚
资源
返回目录 |