stc12C5A60S2内部AD应用.docx
《stc12C5A60S2内部AD应用.docx》由会员分享,可在线阅读,更多相关《stc12C5A60S2内部AD应用.docx(15页珍藏版)》请在冰豆网上搜索。
stc12C5A60S2内部AD应用
stc12C5A60S2内部AD应用
系统说明:
本人想用STC12C5A60S2自带的A/D对电源电压进行检测(暂定3.3V),晶振:
12M,电压从P1.0口输入,检测后的电压值在1602上进行显示,附上硬件大致原理图,硬件部分是照STC12C5A60S2芯片资料上设计,大家看看有错没?
硬件原理简图(原文件名:
clip_image001.gif)
程序的A/D部分也是从官网资料上搬下来的,只自己稍微改了一下对读取到的A/D转换结果的数据处理,液晶部分是前阵子写的搬过来的。
大家帮我看看哪出问题了?
程序如下:
#include
#include"intrins.h"
#defineucharunsignedchar
#defineuintunsignedint
ucharVo; //A/D转换后换算的电压值
/*DeclareSFRassociatedwiththeADC*/
sfrADC_CONTR = 0xBC; //ADCcontrolregister
sfrADC_RES = 0xBD; //ADChigh8-bitresultregister
sfrADC_RESL = 0xBE;
//sfrADC_LOW2 = 0xBE; //ADClow2-bitresultregister
sfrP1ASF = 0x9D; //P1secondaryfunctioncontrolregister
/*DefineADCoperationconstforADC_CONTR*/
#defineADC_POWER 0x80 //ADCpowercontrolbit
#defineADC_FLAG 0x10 //ADCcompleteflag 模数转换结束标志位
#defineADC_START 0x08 //ADCstartcontrolbit 模数转换启动控制位
//转换速度控制位SPEED0和SPEED1,共四种状态,对应四种转换速度
#defineADC_SPEEDLL0x00 //540clocks
#defineADC_SPEEDL 0x20 //360clocks
#defineADC_SPEEDH 0x40 //180clocks
#defineADC_SPEEDHH0x60 //90clocks
uchartCount;
sbitRS=P0^4;
sbitRW=P0^5;
sbitEN=P0^6;
voidDelayMS(uintms)
{
uinti;
while(ms--)
{
for(i=0;i<120;i++);
}
}
/*----------------------------
Softwaredelayfunction
----------------------------*/
voidDelay(uintn)
{
uintx;
while(n--)
{
x=5000;
while(x--);
}
}
/*----------------------------
InitialADCsfr
----------------------------*/
voidInitADC()
{
P1ASF=0x01; //选择P1.0作为A/D输入通道
ADC_RES=0; //清0
ADC_CONTR=ADC_POWER|ADC_SPEEDLL; //0x10|0x00=0x10:
开电源和设置A/D转换速度
Delay
(2); //ADCpower-onanddelay
}
/*----------------------------
GetADCresult
----------------------------*/
ucharGetADCResult(ucharch)
{
ADC_CONTR=ADC_POWER|ADC_SPEEDLL|ch|ADC_START;//0x00|0x00|ch|0x08:
选择A/D输入通道,开始A/D转换
_nop_(); //Mustwaitbeforeinquiry,
_nop_(); //设置ADC_CONTR寄存器后需加4个CPU时钟周期的延时,才能保证值被写入ADC_CONTR寄存器
_nop_();
_nop_();
while(!
(ADC_CONTR&ADC_FLAG));//Waitcompleteflag
ADC_CONTR&=~ADC_FLAG; //CloseADC
Vo=ADC_RES*5*10/256; //ReturnADCresult(为显示整数,这里将电压值扩大了十倍)
returnVo;
}
ucharRead_LCD_State()
{
ucharstate;
RS=0;
RW=1;
EN=1;
DelayMS
(1);
state=P2;
EN=0;
DelayMS
(1);
returnstate;
}
voidLCD_Busy_Wait()
{
while((Read_LCD_State()&0x80)==0x80);
DelayMS(5);
}
voidWrite_LCD_Data(uchardat) //写数据到1602
{
LCD_Busy_Wait();
RS=1;
RW=0;
EN=0;
P2=dat;
EN=1;
DelayMS
(1);
EN=0;
}
voidWrite_LCD_Command(ucharcmd) //写命令
{
LCD_Busy_Wait();
RS=0;
RW=0;
EN=0;
P2=cmd;
EN=1;
DelayMS
(1);
EN=0;
}
voidInit_LCD() //1602 初始化
{
Write_LCD_Command(0x38);
DelayMS
(1);
Write_LCD_Command(0x01); //清屏
DelayMS
(1);
Write_LCD_Command(0x06); //
DelayMS
(1);
Write_LCD_Command(0x0c);
DelayMS
(1);
}
voidSet_LCD_POS(ucharp)
{
Write_LCD_Command(p|0x80);
}
voidDisplay_LCD_String(ucharp,uchar*s)//1602显示
{
uchari;
Set_LCD_POS(p);
for(i=0;i<16;i++)
{
Write_LCD_Data(s);
DelayMS
(1);
}
}
voidFormat_DateTime(uchard,uchar*a)
{
a[0]=d/10+'0';
a[1]=d%10+'0';
}
//写入液晶第二行
voiddisplay(ucharadd,uchardate)
{
ucharshi,ge;
shi=date/10+'0';
ge=date%10+'0';
Write_LCD_Command(0x80+0x40+add);
Write_LCD_Data(shi);
Write_LCD_Data(ge);
}
//写入液晶第一行
voiddisplay1(ucharadd,uchardate)
{
ucharshi,ge;
shi=date/10;
ge=date%10;
Write_LCD_Command(0x80+add);
Write_LCD_Data(0x30+shi); //0x30即48(十进制)对应的ASCAII码为字符‘0’
Write_LCD_Data(0x30+ge);
}
voidmain()
{
Init_LCD();
InitADC();
while
(1)
{
GetADCResult(0);
Display_LCD_String(0,"dianya:
");
display1(7,Vo);
Display_LCD_String(9,"V ");
DelayMS(1000);
}
}
程序二:
*文件名:
AD_CAIYANG.C
*功能:
使用AD采集电压显示在LCD
*说明:
转自网络,本人验证通过
****************************************************************************/
#include
#defineuintunsignedint
#defineucharunsignedchar
sbitCS=P2^0;//LCD12864串行通信片选
sbitSID=P2^1;//LCD12864串行通信数据口
sbitSCLK=P2^2;//LCD12864串行通信同步时钟信号
sbitPSB=P2^5;//LCD12864并/串选择:
H并行L串行
unsignedinttemp1,sh1,ge1,n1,m1;
unsignedcharad_result_data[10];//AD转换高八位
unsignedcharad_result_low2[10];//AD转换低八位
unsignedcharad_result_total[10];//AD转换总十位
unsignedcharad_average_result;//AD转换十次的平均值
unsignedcharAin,Vin;
unsignedcharb,t,R;
chartp=0;
unsignedcharcodema1[6]={0xb5,0xe7,0xd1,0xb9,0xa1,0xc3};//电压:
unsignedcharcodema2[]={"."};
ucharcodedisp1[]={"提示:
按1键进入"};
ucharcodedisp2[]={"功能选择界面."};
unsignedcharcodenum0[]={0xa3,0xb0};
unsignedcharcodenum1[]={0xa3,0xb1};
unsignedcharcodenum2[]={0xa3,0xb2};
unsignedcharcodenum3[]={0xa3,0xb3};
unsignedcharcodenum4[]={0xa3,0xb4};
unsignedcharcodenum5[]={0xa3,0xb5};
unsignedcharcodenum6[]={0xa3,0xb6};
unsignedcharcodenum7[]={0xa3,0xb7};
unsignedcharcodenum8[]={0xa3,0xb8};
unsignedcharcodenum9[]={0xa3,0xb9};
//-------模块延时程序----------------------------1ms
voiddelay1ms(uintdelay1ms)//STC11F60XE,22.1184M,延时1ms
{
uinti,j;
for(;delay1ms>0;delay1ms--)
for(i=0;i<7;i++)
for(j=0;j<210;j++);
}
voiddelay(uintdelay)//STC11F60XE,22.1184M,延时170us
{
uinti,j;
for(;delay>0;delay--)
for(i=0;i<124;i++);
for(j=0;j<124;j++);
}
/*******************************************************
AD转换程序
*******************************************************/
voidAD_initiate()//初始化函数
{
ES=0;
TMOD=0x21;//定时计数器方式控制寄存器,"自动重装,16位计数器".
SCON=0x50;//串行控制寄存器,方便在串口助手那观察
TH1=0xfa;
TL1=0xfa;
TR1=1;
}
voidADC_Power_On()//AD转换电
{
ADC_CONTR|=0x80;
delay(5);//必要的延时
}
voidget_ad_result()//取AD结果函数,它是十位AD转换,每十次平均,最后取低八位作为AD采样数据
{
uinti,q=0;
for(i=0;i<10;i++)
{
tp=0;
ADC_RES=0;//高八位数据清零,STC12C5A60S2AD数据寄存名与STC12C54××系列不同
ADC_RESL=0;//低两位清零
ADC_CONTR|=0x08;//启动AD转换
while(!
tp)//判断AD转换是否完成
{
tp=0x10;
tp&=ADC_CONTR;
}
ADC_CONTR&=0xe7;
ad_average_result=ADC_RES;
q=q+ad_average_result;
}
ad_average_result=q/10;
//ad_average_result=ad_average_result*4*5000/1024;
}
/************************AD转换结束***********************/
voidsend_ad_result()//取AD结果函数发送到串口,方便调试
{
SBUF=n1;
while(TI==0);
TI=0;
delay1ms(100);
//SBUF=R>>4;
}
//---------------------电压采样程序-------------------------
voidcaiyangP10()//测电压
{
P1M0|=0x01;//设P1_0为开漏模式如:
P1_0=#00000000B
P1M1|=0x01;
ADC_CONTR=0xe0;//设置P1.0为输入AD转换口
delay
(2);
get_ad_result();//取转换数据
Vin=ad_average_result;
R=Vin;
}
/*-----------写控制字到LCD12864------------*/
voidwrite_cmd(ucharcmd)
{
uchari;
uchari_data;
i_data=0xf8;//命令控制字:
11111000写指令11111010写数据11111100读状态11111110读数据
CS=1;//片选置高,才能进行读写操作
SCLK=0;
/*----------写命令控制字-----------------*/
for(i=0;i<8;i++)//循环八次,每次读取一位数据
{
SID=(bit)(i_data&0x80);//bit表示取其最高位
SCLK=0;
SCLK=1;//正跳变写入指令
i_data=i_data<<1;//左移一位
}
/*---------------------------------------*/
/*----------写指令高四位-----------------*/
i_data=cmd;
i_data=i_data&0xf0;//把低四位置0
for(i=0;i<8;i++)//循环八次,每次读取一位数据
{
SID=(bit)(i_data&0x80);//bit表示取其最高位
SCLK=0;
SCLK=1;//正跳变写入指令
i_data=i_data<<1;//左移一位
}
/*---------------------------------------*/
/*----------写指令低四位-----------------*/
i_data=cmd;
i_data=i_data<<4;//左移四位,把低四位的数据移到高四位,再把低四位置0
for(i=0;i<8;i++)//循环八次,每次读取一位数据
{
SID=(bit)(i_data&0x80);//bit表示取其最高位
SCLK=0;
SCLK=1;//正跳变写入指令
i_data=i_data<<1;//左移一位
}
/*-----------------------------------------*/
CS=0;//把片选置低
delay1ms(5);//延时是因为没有进行忙检测,适当的延时可以不进行忙检测
}
/*-----------------------------------------*/
/*------------写数据到LCD12864-------------*/
voidwrite_dat(uchardat)
{
uchari;
uchari_data;
i_data=0xfa;
CS=1;
for(i=0;i<8;i++)
{
SID=(bit)(i_data&0x80);
SCLK=0;
SCLK=1;
i_data=i_data<<1;
}
i_data=dat;
i_data=i_data&0xf0;
for(i=0;i<8;i++)
{
SID=(bit)(i_data&0x80);
SCLK=0;
SCLK=1;
i_data=i_data<<1;
}
i_data=dat;
i_data=i_data<<4;
for(i=0;i<8;i++)
{
SID=(bit)(i_data&0x80);
SCLK=0;
SCLK=1;
i_data=i_data<<1;
}
CS=0;
delay1ms(5);
}
/*-----------------------------------------*/
/*--------------显示坐标-------------------*/
voidlcd_pos(ucharx,uchary)//汉字显示坐标,x为哪一行,y为哪一列
{
ucharpos;
if(x==0)
x=0x80;//第一行
elseif(x==1)
x=0x90;//第二行
elseif(x==2)
x=0x88;//第三行
elseif(x==3)
x=0x98;//第四行
pos=x+y;//显示哪一行(总共有4行)哪一竖(总共有8竖,每16列为1竖)
write_cmd(pos);
}
/*-----------------------------------------*/
/*--------------显示8个汉字-------------------*/
voiddisp_hanzi(ucharcode*chn)
{
uchari;
write_cmd(0x30);//基本指令操作方式
for(i=0;i<16;i++)//16列*8个汉字=128(刚好)
write_dat(chn[i]);
}
/*-----------------------------------------*/
/*--------------显示数字-------------------*/
voiddisp_num(ucharcode