-
实验名称:
简易数字电压表。
(测试范围
0
——
5V
,如需加大范围,改变相关数据类型,鉴
于
S
TC12C5A60S2
内部
AD
的特
性,有相当误差)
实验目的:
p>
通过
STC12C5A60S2
自带
AD
采集外部电压,将采集到的
AD
值传给
LCD12864
。
单片机上电后如未接入任何电压,将显示上次输入电压
实验手段:
STC12C5A60S2
单片机内部
AD
、内部
EEPROM<
/p>
、
LCD12864(ks108
控制器
,
不带字
库
)
、
DD900
开发板
< br>
实验原理图:
其中
P1.0
为电压输入端,电压输入引出一根杜邦线即可。
(主要接法)
(补充接法)
说明:
DD900
< br>开发板在
VEE
端接的电阻值只匹配他们店自带的
12864
(不带字库型)
,实验
结果模糊不可见。原因是对比度不够,也就是
VO
端电压不匹配。实验电路主要参考左图,
对
VO
端、
VEE
端接法请参考补充接法。实际电路电阻值接
50K
,事实上可自我调节阻值
大小。
实验结果:
基本完成每个模块的功能。不足之处:现实运用中,电压表测量电压时,如果
没有输入
的话,电压表应显示为
0
,本实验结果是未输入时,电压飘忽不
定。原因:
AD
采
集数据不稳定的原因
是因为未输入时电压输入通道为悬空状态,
AD
默认为电压不定
,所以
会出现上述状况。在有电压输入的时候,状况良好,漂移少见。因为加入
EEPROM
模块,
本想把悬空状态给和谐掉。
我也尝试两者间不同(悬空的时候变化剧烈,时刻变化,是否可
以用程序的方法和谐??
)
,事实上我试了一个程序思路,发现液晶数值即使在稳定状态,
也可能不仅仅是前后两次对比的结果,可能是多次的结果,由于液晶显示需要一定的时间,
这样的话,只需要隔一定时间保持相同的值与最先采集
的值相等即可。本程序采用的是
50
次
AD
结果计算平均值,如需更加稳定,可以考虑中值平滑滤波算法。
各个子模块介绍:
STC12C5A60S2
内部自带
AD.
IO
初始化
+AD
初始化
+AD
采集开始
+
关闭
AD(AD
电源
也可不关闭,省电下可考虑
)
IO
初始化:
STC12c5a60s2
内部
p>
AD
的八个通道在
P1
口,上电默认为输入输出准双向口模式。使用
AD
时要先将
IO
口设置为
AD
输入模式。对
P1M0/P1M1
寄存器进行操作
AD
初始化:
ADC_CONTR
(特别要注意的地方是每给
ADC_CONTR
赋值
操作需要
4
个
nop
< br>指令)
1
p>
)
对
P1
口八个口
中那个口设置为
AD
输入通道
(可设置
为多个通道,
但处理时还是一路一
路)
,即对上图
ADC_CONTR
中
CH
S2 CHS1 CHS0
进行设置。
2
)
ADC
上电。仅仅以为打开
AD
电源,并没有
开始转换。
ADC_POWER
。
3
p>
)对结果寄存器
REL/RESL
清零。<
/p>
4
)通过设置
SPEED1
SPEED0
来设置四种不同
AD
采
集的速度。与晶振相关。
AD
采集开始:
设置
ADC_START
的值为
1
。
ADC-FLAG
:
ADC
中断标志位,如需采用中断方式,
AD
采集后
p>
FLA
置
1
,需软
件清零。
下面是
AD
模块程序:
/*********************************************** *********
********************
单片机
IO
(
AD
)初始化
****************/
void IO_ADinit()
{
P1M0|=0x01;
//<
/p>
设
P1_0
为开漏模式
< br>
如:
P1_0=
#00000000B
P1M1|=0x01;
ADC_CONTR=0xe0;
//
设置
P1.0
为输入
AD
< br>转换口
_nop_();
//ADC_CONTR
需要四个指令延时
_nop_();
_nop_();
_nop_();
}
/**
**************************************************
****
*******************AD
上电
*******************************/
void ADC_Power_On()
{
ADC_CONTR|=0x80;
_nop_();
_nop_();
_nop_();
_nop_();
//A
DC_CONTR
需要四个指令延时
}
/*************
*******************************************
********************AD
转换获取
< br>AD
值
**********************
*/
void get_ad_result()
//
取<
/p>
AD
结果函数。
{
uint i,q=0;
for(i=0;i<10;i++)
//AD
转换循环
10
次取平均值
{
tp=0;
ADC_RES=0;
ADC_RESL=0;
ADC_CONTR|=0x08;
while(!tp)
{
tp=0x10;
tp&=ADC_CONTR;
}
ADC_CONTR&=0xe7;
ad_average_result=ADC_RES;
q=q+ad_average_result;
}
ad_average_result=q/10;
}
/**************
********************************************
*******************AD
转换调用程序
*************************/
void
ADCONVERT()
{
ADC_Power_On();
IO_ADinit();
get_ad_result();
}
//
高八位数据清零
,STC12C5A60S2
//
低两位清零
//
启动
AD
转换
//
判断
A
D
转换是否完成
STC12C5A60S2
内部
EEPROM
介绍
原理:运用
ISP/IAP
p>
技术将内部
FLASH
当作
EEPROM
来用。
p>
规格大小:手册上仅有
12C560S2
,
可能漏写
A
。内部
EEPROM
存储空间为
1K.
。
注意事
项:在进行
EEPROM
操作时,一般应将
EA=0
,待数据处理完毕再打开中断。
使用:
打
开
IAP
、从
EEPROM
处读数据、写数据、擦除扇区(每进行一次写操作,都要进行擦除)
p>
、关闭
IAP
。
IAP_CMD
< br>命令中需要变化的只有
MS1 MS0
也就是下图的
B1
B0
;三个操作:读、写、擦。
IAP
_TRIG
:
如果用到
IAP_CMD
这个命令的话,要想它动作,必须给
IAP_TRIG
赋值如下来触发。
IAP_TRIG = 0x5A;
IAP_TRIG = 0xA5;
IAP_CONTR:
WT2/W
T1/WT0
三个参数设置。
内部<
/p>
EEPROM
完成读写擦操作所需时间,根据所接晶振设置。
p>
IAPEN
;
IAPEN=1
,允许
FLASH
编
程。在打开
IAP
的时候要置
1
;
IAPEN=0
,不允许
FLASH
编程。
下面是
IAP
模块程序。
/**
函
数
名:
Open_IAP*
功能描述:允许
ISP/IAP */
void Open_IAP(void)
{
EA=0;
//
防止被中断打断
IAP_CONTR = 0x80;
//
充许
I
SP/IAP
,系统时钟
<20MHz
时,设置等待时间
WT2,WT1,WT0(010)
}
/**
函
数
名:
Close_IAP
*
功能描述:禁止
ISP/IAP */
void Close_IAP(void)
{
IAP_CONTR =
0x00;
//
禁止
ISP/IAP
IAP_ADDRH = 0xFF;
p>
//
将
IAP
操作
地址的高八位与低八位移到非本次操作地址处(防止
IAP
误操
作)
IAP_ADDRL = 0xFF;
EA=1;
}
/*
*
函
数
名:
Read_IAP_Byte
*
功能描述:从
EEPROM
指定的单元
读取一个字节数据
*/
uint
Read_IAP_Byte(uint addr)
{
IAP_CMD = 0x01;
IAP_ADDRH = (addr &
0xFF00)>>8;
IAP_ADDRL = addr & 0x00FF;
IAP_TRIG =
0x5A;
IAP_TRIG = 0xA5;
//<
/p>
对
IAP_TRIG
先写
0x5A
再写
0xA5
,
p>
ISP/IAP
命令才会生效
return IAP_DA
TA;
}
/* *
函
数
名:
Write_IAP_Byte
*
功能描述:把一个字节数据写入
E
EPROM
指定的单元
,
写入数据前应
先擦除扇区
*
输入参数:
addr:16bit
地址;
writeVal
:
要写入的数据
*/
void Write_IAP_Byte(int
addr, uint writeVal)
{
IAP_CMD = 0x02;
IAP_ADDRH = (addr &
0xFF00)>>8;
IAP_ADDRL =
addr & 0x00FF;
IAP_DA
TA = writeVal;
IAP_TRIG = 0x5A;
IAP_TRIG =
0xA5;
//
对
IA
P_TRIG
先写
0x5A
再写
0xA5
,
ISP/IAP
< br>命令才会生效
}
/* *
函
数
名:
Erase_IAP_Sector
*
功能描述:擦除扇区
,
没有字节擦除
*
输入参数:
addr
:扇区地址
,
扇区中任意一个字节地址都是该扇区地
址
*/
void
Erase_IAP_Sector(int addr)
{
IAP_CMD = 0x03;
IAP_ADDRH = (addr & 0xFF00)>>8;
IAP_ADDRL = addr & 0x00FF;
IAP_TRIG = 0x5A;
IAP_TRIG = 0xA5;
//<
/p>
对
IAP_TRIG
先写
0x5A
再写
0xA5
,
p>
ISP/IAP
命令才会生效
}
关于<
/p>
12864
模块
这个模块我就不说了,网上程序一大堆,原理图也有。
我遇到的问题是对比度调节(硬件连接不对,上有提到)
p>
。如果显示一部分,应该是延时问
题。加延时或者减少晶振先验证一
下。
整个程序的源代码:
(有待规范跟完善)
#include
#include
#include
#define
uchar
unsigned char
#define
uint
unsigned int
#define Lcd_Bus
P0 //MCU P0<------> LCM
#define Disp_On
0x3f//
开显示
#define
Disp_Off 0x3e//
关显示
#define Col_Add
0x40//
列地址
#define
Page_Add 0xb8//
页地址
#define Start_Line
0xc0//
起始页
sbit
cs1=P2^3; //Master chip enable
sbit
cs2=P2^4; //Slave chip enable
sbit
Enable=P2^2; // mode Enable single
sbit
Di=P2^0; //Data or Instrument Select
sbit RW=P2^1; //Write or Read
sbit Lcd_Rst=P2^5; //Lcm reset
unsigned int a,i,j,k;
unsigned char tp,p,plus;
uint Vin,count;
uint
ad_average_result;
unsigned char
code sz0[]={
//
数字
0
8*16 //
0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,
0x0F,0x10,0x20,0x20,0x10,0x0F,0x00,
};
unsigned char code sz1[]={
//
数字
1
8*16 //
0x00,0x10,0x10,0xF8,0x00,0x00,0x00,0x00,0x00,
0x20,0x20,0x3F,0x20,0x20,0x00,0x00,
};
unsigned char code sz2[]={
//
数字
2
8*16 //
0x00,0x70,0x08,0x08,0x08,0x88,0x70,0x00,0x00,
0x30,0x28,0x24,0x22,0x21,0x30,0x00,
};
unsigned char code sz3[]={
//
数字
3
8*16 //
0x00,0x30,0x08,0x88,
0x88,0x48,0x30,0x00,0x00,0x18,0x20,0x20,0x20,0x11,
0x0E,0x00,
};
unsigned char code sz4[]={
//
数字
4
8*16 //
0x00,0x00,0xC0,0x20,
0x10,0xF8,0x00,0x00,0x00,0x07,0x04,0x24,0x24,0x3F,
0x24,0x00,
};
unsigned char code sz5[]={
//
数字
5
8*16 //
0x00,0xF8,0x08,0x88,
0x88,0x08,0x08,0x00,0x00,0x19,0x21,0x20,0x20,0x11,
0x0E,0x00,
};
unsigned char code sz6[]={
//
数字
6
8*16 //
0x00,0xE0,0x10,0x88,
0x88,0x18,0x00,0x00,0x00,0x0F,0x11,0x20,0x20,0x11,
0x0E,0x00,
};
unsigned char code sz7[]={
//
数字
7
8*16 //
0x00,0x38,0x08,0x08,
0xC8,0x38,0x08,0x00,0x00,0x00,0x00,0x3F,0x00,0x00,
0x00,0x00,
};
unsigned char code sz8[]={
//
数字
8
8*16 //
0x00,0x70,0x88,0x08,
0x08,0x88,0x70,0x00,0x00,0x1C,0x22,0x21,0x21,0x22,
0x1C,0x00,
};
unsigned char code sz9[]={
//
数字
9
8*16 //
0x00,0xE0,0x10,0x08,
0x08,0x10,0xE0,0x00,0x00,0x00,0x31,0x22,0x22,0x11,
0x0F,0x00,
};
unsigned char
code sz11[]={0x80,0x80,0x80,0x00,0x00,0x80,0x80,0x
80,0x00,0x01,0x0E,0x30,0x08,0x06,0x01,0x00};
unsigned char code sz10[]={0x00,0x00,0x
00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x
00,0x00,0x00,0x00};
unsigned char code
*shuzi[]={sz0, sz1, sz2, sz3, sz4, sz5, sz6, sz7,
sz8, sz9,sz10};
/*****************************
< br>字模
,
此字体下对应的
点阵为:宽
x
高
=1
6x16
*****************************/
unsigned char code
Chinese_character[][32]=
{
{
0x10,0x60,0x01,0xF6,0x00,0x10,0xF8,0x17,0x34,0x54,
0x14,0x14,0xF4,0x04,0x04,0x00,0x04,0x04,0xFF,0x00,
0x01,0x01,0x1
F,0x11,0x13,0x15,0x51,0x91
,0x7F,0x11,0x11,0x00},/*
海
{0x00,0x80,0x60,0xF8,0x0F,0x02,0xF8,0x08,0
x0C,0x0B,0x0A,0x08,0x08,0xF8,0x00,0x00,0x01,0x00,0
x00,0x7F,0x00,0x00,0x
7F,0x21,0x21,0x21,
0x21,0x21,0x21,0x7F,0x00,0x00},/*
伯
{0x00,0x00,0xF8,0x48,
0x48,0x48,0x48,0xFF,0x48,0x48,0x48,0x48,0xF8,0x00,
0x00,0x00,0x00,0x00,0x0F,0x04,0x04,0x04,0x0
4,0x3F,0x44,0x44,0x44,0x44,0x4F,0x40,0x70,0x00
},/*
电
{0x00,0x00,0x02,0x02,0x02,0x02,0x02,0xE2,0x12,0x0A
,0x06,0x02,0x00,0x80,0x00,0x00,0x01,0x01,0x01,0x01
,0x01,0x41,0x8
1,0x7F,0x01,0x01,0x01,0x0
1,0x01,0x01,0x01,0x00},/*
子
p>
-
-
-
-
-
-
-
-
-
上一篇:2017数字IC设计工程师招聘面试笔试100题附答案
下一篇:_翻译原文