目录
AD模数转换
XPT2046.c
XPT2046.h
main.c
DA数模转换
main.c
上一篇博客讲了AD/DA转换的工作原理,也介绍了运算放大器的工作原理,这节开始代码演示!
AD模数转换
新创建一个工程:AD模数转换
第一个工程将用到LCD1602和Delay函数,所以首先将我们之前讲过的代码模块添加进来
然后创建主程序main.c,XPT2046.c,XPT2046.h文件。
开始代码讲解:
XPT2046.c
首先根据原理图重定义引脚:
#include <REGX52.H>
#include <INTRINS.H>//引脚定义
sbit XPY2046_DIN=P3^4;
sbit XPY2046_CS=P3^5;
sbit XPY2046_DCLK=P3^6;
sbit XPY2046_DOUT=P3^7;
接下来就根据上一篇博客讲过的这个时序来定义函数
将DLCK拉高有立马拉低的过程中,手册上显示这些过程基本都是纳秒级别的,而我们单片机IO口的翻转周期是1微秒这么长,足够操作这些过程了。
将命令字节发送结束后时序就完成到这了
然后由于下降沿是表示读出,所以我们要读取数据之后首先将DCLK拉高,再来一个下降沿,数据才会过来。
unsigned int XPT2046_ReadAD(unsigned char Command)
{unsigned char i;//发送/读取的次数unsigned int Data=0;//数据XPY2046_DCLK=0;//片选之前先初始化一下DCLK//这一步不写也没关系,因为每次任务结束之后DCLK都会拉低到低电平的。XPY2046_CS=0;//片选//反复8次发送命令字的8位数据for(i=0;i<8;i++){XPY2046_DIN=Command&(0x80>>i);//将命令字8位数据从左往右依次放到DIN线上XPY2046_DCLK=1;//DCLK拉高时输入数据XPY2046_DCLK=0;//立马拉低这个过程是1us,足够发送一位数据了。}//发送命令字的整个时间肯定超过TACO这个时间了,//所以读取之前可以不延时。//反复16次读取两个字节for(i=0;i<16;i++){XPY2046_DCLK=1;//下降沿是表示读出,所以首先将DCLK拉高,XPY2046_DCLK=0;//再来一个下降沿,数据才会过来//如果XPY2046_DOUT=1就把1赋值给Data,//从左往右依次判断XPY2046_DOUT的16位数据并赋值给Dataif(XPY2046_DOUT){Data|=(0x8000>>i);}}XPY2046_CS=1;//释放CSif(Command&0x08)//如果命令字的第5位是1表示是在8位转换的模式下{return Data>>8;//在8位转换的模式下,要把最终的数据右移8位截取低8位的数据}else{return Data>>4;//在12位转换的模式下,要把最终的数据右移4位截取低12位的数据}
}
在8位转换的模式下,要把最终的数据右移8位截取低8位的数据。
在12位转换的模式下,要把最终的数据右移4位截取低12位的数据。
读取数据时,后面的四位0填充可以不读,那么读取数据时直接i<12,也可以读出来再右移。
最后我们只要调用这个函数就可以得到AD值(范围:8位为0~255,12位为0~4095)。
XPT2046.h
接下来我们看一下命令字怎么写:
XPT2046芯片手册上的介绍:
PD1还选择内部的参考电压,如果给它1就选择内部参考电压2.5V,它就对2.5V进行等分。但是我们一般不用内部参考电压,我们用外部电压,PD1=0就外部参考电压,就是原理图的上的VREF,为5V。
我们的开发板上的这个ADC模块利用的是单端模式,SER/DFR=1
A2,A1,A0的配置要看这个表
A2,A1,A0组合选择,我们只要主要看表的前半部分就可以
PS:YN是-Y,XP是+X,YP是+Y
如果说我们要测+X的话,就把A2,A1,A0置为001或者011
如果想测电池电压(电池电压并不是测电池,它也当做是一个通用的AD)就将A2,A1,A0置为010
如果我们要测辅助输入的电压,就置为110
-Y端(YN)直接接地,不用测,所以直接不用管
如果我们要测YP(+Y),就置为101
最后我们配置的控制字一般是:
S=1(起始位)
A2,A1,A0=001或者011测+X(XP),010测VBAT,110测AUXIN,101测+Y(YP)
MODE=1/0 (8位转换和12位转换都可以试一下)
SER/DFR=1(单端模式)
PD1=0(外部参考电压)
PD0=0(低功耗模式)
为了方便,我们直接将这8位数据组合起来的命令字加一个宏定义,要用的时候可以直接调用就好了(声明为外部可调用)
#ifndef __XPT2046_H__
#define __XPT2046_H__//选择8位转换模式
#define XPT2046_VBAT_8 0xAC
#define XPT2046_AUX_8 0xEC
#define XPT2046_XP_8 0x9C //0xBC
#define XPT2046_YP_8 0xDC//选择12位转换模式
#define XPT2046_VBAT_12 0xA4
#define XPT2046_AUX_12 0xE4
#define XPT2046_XP_12 0x94 //0xB4
#define XPT2046_YP_12 0xD4unsigned int XPT2046_ReadAD(unsigned char Command);#endif
main.c
接下来就分别测电位器,热敏电阻和光敏电阻
PS:电位器就是可调电阻
我们将定义好的命令字对应传给我们XPT2046_ReadAD()函数,然后它结果显示在LCD1602液晶屏上
#include <REGX52.H>
#include "Delay.h"
#include "LCD1602.h"
#include "XPT2046.h"unsigned int ADValue;void main(void)
{LCD_Init();LCD_ShowString(1,1,"ADJ NTC GR");//第一行显示"ADJ NTC GR"分别表示可调电阻,热敏电阻,光敏电阻while(1){ADValue=XPT2046_ReadAD(XPT2046_XP_12); //读取AIN0,可调电阻LCD_ShowNum(2,1,ADValue,4); //显示AIN0ADValue=XPT2046_ReadAD(XPT2046_YP_12); //读取AIN1,热敏电阻LCD_ShowNum(2,6,ADValue,4); //显示AIN1ADValue=XPT2046_ReadAD(XPT2046_VBAT_12); //读取AIN2,光敏电阻LCD_ShowNum(2,11,ADValue,4); //显示AIN2Delay(100);//由于光敏电阻和热敏电阻非常敏感,//所以阻值变化非常快,读出来的数字电压变化也非常快//延迟是为了读出来的数据能够显示的时间长一点点,//这样我们就能看清数据,要不然数据变换更新太快我们都看不清楚。}
}
效果请看视频:
AD模数转换
以上就是AD数模转换的代码演示!
DA数模转换
接下来开始演示第二个代码,
新创建一个工程:DA数模转换
DA转换可以直接用PWM来实现,直接把之前写电机那一篇的程序添加进来修改一下。
main.c
首先是根据DA的原理图改IO口的定义
#include <REGX52.H>
#include "Delay.h"
#include "Timer0.h"sbit DA=P2^1;
然后将所有Motor都改成DA,我们实现一个呼吸灯的效果就好了,所以就不用独立键盘相关的配置了,全部删掉:
unsigned char Counter,Compare; //计数值和比较值,用于输出PWM
unsigned char i;void main()
{Timer0_Init();while(1){for(i=0;i<100;i++){Compare=i; //设置比较值,改变PWM占空比Delay(10);}for(i=100;i>0;i--){Compare=i; //设置比较值,改变PWM占空比Delay(10);}}
}void Timer0_Routine() interrupt 1
{TL0 = 0x9C; //设置定时初值TH0 = 0xFF; //设置定时初值Counter++;Counter%=100; //计数值变化范围限制在0~99if(Counter<Compare) //计数值小于比较值{DA=1; //输出1}else //计数值大于比较值{DA=0; //输出0}
}
如果看不懂这里的话可以去看一下我这两篇博客,里面讲了PWM的原理和代码演示:
单片机学习笔记---直流电机驱动(PWM)-CSDN博客
单片机学习笔记---LED呼吸灯&直流电机调速-CSDN博客
最终效果请看视频:(PS:手机录像的效果会有明显的屏闪)
DA数模转换
以上就是本篇的内容,源码会放在评论区,如有问题可评论区留言!