#define DataPort P0 //定义数据端口 程序中遇到DataPort 则用P0 替换
sbit LATCH1=P2^6//定义锁存使能端口 段锁存
sbit LATCH2=P2^7// 位锁存
unsigned char code DuanMa[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8}
// 显示段码值01234567
unsigned char code WeiMa[]={0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01}
//分别对应相应的数码管点亮,即位码
void Delay(unsigned int t)//函数声明
/*------------------------------------------------
主函数
------------------------------------------------*/
main()
{
unsigned char i=0
while(1)
{
DataPort=WeiMa[i]//取位码
LATCH2=1//位锁存
LATCH2=0
DataPort=DuanMa[i]//取显示数据,段码
LATCH1=1//段锁存
LATCH1=0
Delay(200)//扫描间隙延时,时间太长会闪烁,太短会造成重影
i++
if(8==i)//检测8位扫描完全结束?如扫描完成则从第一个开始再次扫描8位
i=0
}
}
/*------------------------------------------------
延时函数,含有输入参数 unsigned int t,无返回值
unsigned int 是定义无符号整形变量,其值的范围是
0~65535
------------------------------------------------*/
void Delay(unsigned int t)
{
while(--t)
}
不译码指的是不转成BCD码,也就是说如果连接是按顺序连接数码管的八个管脚,在对CH451初始化后,可发送设置,让它用译码方式,(默认不译码),译码后,有个表,发送数据是多少显多少。不译码,需要在程序中写个表,手工译码,也就是数码管的a、b、c...对应的灯亮,总体显一个数。4线串行接口,是和单片机的通信采用串行通信,其中一次传输4个数据,通过CLOCK管教控制,具体请看CH451手册
下面是一段CH451用汇编编写的驱动程序,望对理解有帮助
****************************************************************************
需要主程序定义的参数
CH451_DCLKBIT P3.4 串行数据时钟,上升沿激活
CH451_DIN BIT P3.3 串行数据输出,接 CH451 的数据输入
CH451_LOADBIT P2.3 串行命令加载,上升沿激活
CH451_DOUTBIT P2.2 INT0,键盘中断和键值数据输入,接 CH451 的数据输出
CH451_KEY DATA 7FH 存放键盘中断中读取的键值
****************************************************************************
R452 367 1
ORG 0000H
START:
ACALL CH451_INIT 调用初始化程序
MOV R5,#10H 将要显示的数放入R5中
MOV R4,#04H 将要在第几位上显示放在R4中,最右边是0位
KEYSHOW:
ACALL SCAN1
ACALL CHANGE
SJMP KEYSHOW
SJMP $
****************************************************************************
子程序调用
****************************************************************************
初始化子程序
CH451_INIT:
CLR CH451_DIN先低后高,输出上升沿通知 CH451 选择 4 线串行接口
SETB CH451_DCLK 置为默认的高电平
SETB CH451_DIN
SETB CH451_LOAD
SETB CH451_DOUT 置为输入
CLR IT0 置外部信号为低电平触发
SETB PX0 置高优先级或者低优先级
CLR IE0 清中断标志
SETB EX0 允许键盘中断
MOV B,#04H 设置为键盘与显示开
MOV A,#03H
ACALL CH451_WRITE
RET
****************************************************************************
数码管显示程序
****************************************************************************
转换程序,在R4位显示R5值
CHANGE:
MOV A,R5
ACALL TTA 对应M2t1板的数码管转换
MOV R2,A
MOV A,R4
ACALL TTB 对应m2t1板的数码管位置转换
MOV B,A
MOV A,R2
ACALL CH451_WRITE
RET
M2T1板数码管对应表
TTA: MOV DPTR,#TAB_A
MOVC A,@A+DPTR
RET
对应m2t1板的数码管位置转换
TTB: MOV DPTR,#TAB_B
MOVC A,@A+DPTR
RET
TAB_A:
DB 0BEH0 显示数
DB 24H 1
DB 0EAH2
DB 0E6H3
DB 74H 4
DB 0D6H5
DB 0DEH6
DB 0A4H7
DB 0FEH8
DB 0F6H9
DB 0FCHA
DB 5EH B
DB 4AH C
DB 0BEHD
DB 0DAHE
DB 0E4HF
DB 00H 10H无显示
DB 0FEH11H对于数码管0位倒过来焊接的人,可以显示°C
DB 40H 12H - 号
TAB_B:
DB 0AH0 显示数码管号
DB 09H1
DB 0BH2
DB 08H3
DB 0CH4
DB 0DH5
DB 0EH6
DB 0FH7
****************************************************************************
键盘扫描程序
****************************************************************************
SCAN1:MOV C,CH451_DOUT
JC SCAN1
ACALL CH451_READ
MOV R1,A
C0: CJNE A,#40H,C1
MOV R5,#00H
AJMP TES
C1: CJNE A,#43H,C2
MOV R5,#01H
AJMP TES
C2: CJNE A,#41H,C3
MOV R5,#02H
AJMP TES
C3: CJNE A,#42H,C4
MOV R5,#03H
AJMP TES
C4: CJNE A,#48H,C5
MOV R5,#04H
AJMP TES
C5: CJNE A,#4BH,C6
MOV R5,#05H
AJMP TES
C6: CJNE A,#49H,C7
MOV R5,#06H
AJMP TES
C7: CJNE A,#4AH,SCAN1
MOV R5,#07H
AJMP TES
TES:
RET
****************************************************************************
移位程序
****************************************************************************
DELAY_1S 延迟1秒
DELAY_1S:
MOV R7,#20
DEL1:MOV R6,#200
DEL2:MOV R3,#248
DJNZ R3,$
DJNZ R6,DEL2
DJNZ R7,DEL1
RET
左四位左移位
/*LIFT:
MOV B,#03H
MOV A,#00H
ACALL CH451_WRITE
INC R5
ACALL CHANGE
ACALL DELAY_1S
CJNE R5,#09H,LIFT
SJMP START
RET*/
****************************************************************************
串口通信读出写入程序
****************************************************************************
CH451_WRITE:
CLR EX0 禁止键盘中断
CLR CH451_LOAD 命令开始,此命令可以放在后面
MOV R7,#08H 将 ACC 中 8 位送出
CH451_WRITE_8: RRC A低位在前,高位在后
CLR CH451_DCLK
MOV CH451_DIN,C 送出一位数据
SETB CH451_DCLK 产生时钟上升沿通知 CH451 输入位数据
DJNZ R7,CH451_WRITE_8 位数据未完继续
MOV A,B
MOV R7,#04H 将 B 中 4 位送出
CH451_WRITE_4: RRC A低位在前,高位在后
CLR CH451_DCLK
MOV CH451_DIN,C 送出一位数据
SETB CH451_DCLK 产生时钟上升沿通知 CH451 输入位数据
DJNZ R7,CH451_WRITE_4 位数据未完继续
SETB CH451_LOAD 产生加载上升沿通知 CH451 处理命令数据
SETB EX0 允许键盘中断
RET
输入键值子程序
CH451_READ: CLR EX0 禁止键盘中断
CLR CH451_LOAD 命令开始
MOV A,#07H 读取键值命令的高 4 位 0111B
MOV R7,#04H 忽略 12 位命令的低 8 位
CH451_READ_4: RRC A低位在前,高位在后
CLR CH451_DCLK
MOV CH451_DIN,C 送出一位数据
SETB CH451_DCLK 产生时钟上升沿锁通知 CH451 输入位数据
DJNZ R7,CH451_READ_4 位数据未完继续
SETB CH451_LOAD 产生加载上升沿通知 CH451 处理命令数据
CLR A先清除键值单元以便移位
MOV R7,#07H 读入 7 位键值
CH451_READ_7:
MOV C,CH451_DOUT 读入一位数据
CLR CH451_DCLK 产生时钟下升沿通知 CH451 输出下一位
RLC A数据移入 ACC,高位在前,低位在后
SETB CH451_DCLK
DJNZ R7,CH451_READ_7 位数据未完继续
CLR IE0 清中断标志,读 *** 作过程中有低电平脉冲
SETB EX0 允许键盘中断
RET
END
刚做过,发给你参考下这是原理图
51单片机简易计算器程序:
#include <reg51.h>
#include <math.h>
#define uchar unsigned char
#define uint unsigned int
//---------定义引脚--------------------
bit clr=0
bit ok=0
bit xiaoshu=0
bit jiego=0
bit first_1=1
bit first_2=1
sbit dout = P3^2
sbit load = P2^0
sbit din = P2^1
sbit dclk = P2^2
sbit beer=P0^1
sbit LCD1602_RS=P2^3
sbit LCD1602_RW=P2^4
sbit LCD1602_E=P2^5
//---------定义变量--------------------
uchar ch451_key=0xff
uchar yun_sign
uchar xiabiao=0
uchar tab[32]
uchar tab1[]={"welcome to use!"}
uchar tab2[]={" make by JunRu!"}
uchar tab3[]={"ERR0R"}
float opr_1=0,opr_temp=0,end=0,a
//---------声明函数--------------------
void ch451_init(void)//CH451初始化
void ch451_write(uint command)//写命令或数据到ch451
uchar ch451_read(void) //读按键值
uchar get_char(void)
void LCD_init(void)//初始化;
void delay(unsigned int k)//延时程序
void LCD_inter_command(unsigned char command)//写入控制字
void LCD_inter_dat(unsigned char dat)//写入要显示的数据
void set_xy(unsigned char x,unsigned char y)//找地址
void write(unsigned char date)//写入字符
void lcdbusy()//查忙时
void display(void)
void spec(void)
void get_end(void)
void hun_he(uchar n)
//-------- 主函数----------------------
void main()
{
uchar i
LCD_init()//LCD初始化;
ch451_init()//CH451初始化
EA = 1//打开中断
LCD_inter_command(0x01)//清屏
for(i=0i<=14i++)
{
LCD_inter_dat(tab1[i])
beer=0
delay(4000)//延时
beer=1
}
LCD_inter_command(0xc0)//从第二行开始显示
for(i=0i<=14i++)
{
LCD_inter_dat(tab2[i])
beer=0
delay(4000)//延时
beer=1
}
delay(0xffff)
delay(0xffff)
LCD_inter_command(0x01)
while(1)
{
if(ok)
{
display()
ok=0clr=1
}
}
}
//----------子函数--------------------
void hun_he(uchar n)
{int j
switch(n)
{
case '+':opr_temp=opr_temp+opr_1break
case '-':opr_temp=opr_temp-opr_1break
case '*':opr_temp=opr_temp*opr_1break
case '/':
{
if(a==0)//减数为零显错
{ LCD_inter_command(0xc0)
for(j=0j<=4j++)
{
LCD_inter_dat(tab3[j])
beer=0
delay(4000)//延时
beer=1
}
}
else
{opr_temp=opr_temp/opr_1}
break
}
default:break}
}
void ch451_init(void)//CH451初始化
{
EX0 = 1
din = 0
din = 1
ch451_write(0x403) //开显示
ch451_write(0x580) //BCD译码方式
}
void ch451_write(uint command)//写命令或数据到ch451
{ uchar i
EX0 = 0
load = 0
for(i=0i<12i++)
{
din = command&1
dclk = 0
command>>=1
dclk = 1
}
load = 1
EX0 = 1
}
uchar ch451_read(void)//读按键值
{ uchar key=0x07
uchar i
EX0=0
load = 0
for(i=0i<4i++)//将0111读入
{
din = key &1
dclk = 0
key>>=1
dclk =1
}
load = 1
key = 0
for(i=0i<7i++) //从CH451读出按键值
{
key<<=1
key|= dout
dclk =0
dclk =1
}
EX0 =1
return key
}
void EX0_ISR(void)interrupt 0 //中断程序
{
uchar temp
ch451_key=ch451_read()//将读出的按键值赋给变量
spec()
if(clr) {LCD_inter_command(0x01)clr=0}
temp=get_char()
if(temp){tab[xiabiao++]=tempLCD_inter_dat(temp)}
if(xiabiao>=16)LCD_inter_command(0xc0)//若大于16,则从第2行开始显示
if(ok) get_end()
beer=0
delay(3000)
beer=1
}
uchar get_char(void)
{
uchar dis=0
uint temp=0,temp1=0
switch(ch451_key)
{
case 0x40:dis='1'break
case 0x41:dis='2'break
case 0x42:dis='3'break
case 0x48:dis='4'break
case 0x49:dis='5'break
case 0x4A:dis='6'break
case 0x50:dis='7'break
case 0x51:dis='8'break
case 0x52:dis='9'break
case 0x58:dis='0'break
case 0x43:dis='+'break
case 0x4B:dis='-'break
case 0x53:dis='x'break
case 0x5B:dis='/'break
case 0x44:dis='!'break
case 0x5A:dis='='
ok=1 //遇到“=”,开始运算
break
case 0x59:dis='.'break//小数点
case 0x5C://删除键
LCD_inter_command(0x01)
xiabiao=0
break
default: break
}
return dis
}
void spec(void) //特殊功能键
{
switch(ch451_key)
{
case 0x4C:LCD_inter_command(0x10){if(xiabiao>0)xiabiao-=1}break//左移
case 0x54:LCD_inter_command(0x14){xiabiao+=1}break //右移
default:break
}
}
void delay(unsigned int k)//延时程序
{
while (k--)
}
void LCD_inter_command(unsigned char command)//写入控制字
{
delay(5000)
LCD1602_RS=0
LCD1602_RW=0
LCD1602_E=1
P1=command
LCD1602_E=0
lcdbusy()
}
void LCD_init(void)//初始化;
{delay(5000)
LCD_inter_command(0x01)//清屏
delay(5000)
LCD_inter_command(0x38)//设置为8位的数据接口,两行显示,5、7点字符
delay(5000)
LCD_inter_command(0x0E)//显示打开,光标开并闪烁
delay(5000)
}
void LCD_inter_dat(unsigned char dat)//写入要显示的数据
{
delay(5000)
LCD1602_RS=1
LCD1602_RW=0
LCD1602_E=1
P1=dat
LCD1602_E=0
lcdbusy()
}
void lcdbusy()//查忙
{
P1=0xFF
LCD1602_RS=0
LCD1602_RW=1
LCD1602_E=1
while((P1&0x80)==1)
}
void display(void)//转化在LCD上显示计算结果
{
int temp=end //浮点数
int i
uint xiao_temp
uint xx//浮点数的整数部分
if (end>-32769&&end<32768)
{
xx=fabs(end)
xiao_temp=(fabs(end)-xx)*1000//取出浮点数的小数部分
LCD_inter_command(0xc0)
if(end<0) LCD_inter_dat('-')beer=0delay(4000)beer=1//判断是否为负数,若是则显示负号
if(xx>9999) LCD_inter_dat((xx/10000)%10+'0')beer=0delay(4000)beer=1
if(xx>999) LCD_inter_dat((xx/1000)%10+'0')beer=0delay(4000)beer=1//在LCD上显示千位的数
if(xx>99)LCD_inter_dat((xx/100)%10+'0') beer=0delay(4000)beer=1//百位
if(xx>9)LCD_inter_dat((xx/10)%10+'0')beer=0delay(4000)beer=1//十位
LCD_inter_dat(xx%10+'0')beer=0delay(4000)beer=1//个位
if(xiao_temp!=0) //显示小数部分
{
LCD_inter_dat('.')beer=0delay(4000)beer=1
LCD_inter_dat((xiao_temp/100)%10+'0')beer=0delay(4000)beer=1
LCD_inter_dat((xiao_temp/10)%10+'0')beer=0delay(4000)beer=1
LCD_inter_dat(xiao_temp%10+'0')beer=0delay(4000)beer=1
}
}
else {LCD_inter_command(0xc0)//从第二行开始显示
for(i=0i<=4i++)
{ LCD_inter_dat(tab3[i])
beer=0
delay(4000)//延时
beer=1
}
}
}
void get_end(void)//计算子程序
{ float xiaoshu=1
uchar fu_flag=0
uchar xiao_flag=0
uchar lianji_sign
uchar i=0
uchar j
uchar n//正负标记符
while(i<=xiabiao)
{
while(tab[i]<=0x39&&tab[i]>=0x30)
{
n=0
opr_1*=10
opr_1+=tab[i++]-0x30
n='+'
}
switch(tab[i])
{
case '.': xiao_flag=1break//遇到小数点跳到“if(xiao_flag)”里
case '!': fu_flag=1break
case '+': xiaoshu=1yun_sign='+'if(opr_temp==0){end=opr_temp=opr_1}else hun_he(lianji_sign)opr_1=0lianji_sign='+'break
case '-': xiaoshu=1yun_sign='-'if(opr_temp==0){end=opr_temp=opr_1}else hun_he(lianji_sign)opr_1=0lianji_sign='-'break
case 'x': xiaoshu=1yun_sign='x'if(opr_temp==0){end=opr_temp=opr_1}else hun_he(lianji_sign)opr_1=0lianji_sign='*'break
case '/': xiaoshu=1yun_sign='/'if(opr_temp==0){end=opr_temp=opr_1}else hun_he(lianji_sign)a=opr_1opr_1=0lianji_sign='/'break
case '=':
switch(yun_sign)//进行运算
{
case '+':end=opr_temp+opr_1break
case '-':end=opr_temp-opr_1break
case 'x':end=opr_temp*opr_1break
case '/':{
if(a==0)//减数为零显错
{ LCD_inter_command(0xc0)
for(j=0j<=4j++)
{
LCD_inter_dat(tab3[j])
beer=0
delay(4000)//延时
beer=1
}
}
else
{end=opr_temp/opr_1}
break
}
default:break
}
ok=1//开始进行显示,标志位置1
xiabiao=0//小数的标志位清零
break
default:break
}
i++
if(xiao_flag)//表示小数
{
while(tab[i]<=0x39&&tab[i]>=0x30)
{
xiaoshu*=0.1
switch(n)
{
case '+': opr_1=opr_1+(tab[i++]-0x30)*xiaoshubreak
case '-': opr_1=opr_1-(tab[i++]-0x30)*xiaoshubreak
default:break}
xiao_flag=0
}
}
if(fu_flag)
{
while(tab[i]<=0x39&&tab[i]>=0x30)
{
n=0
opr_1=-opr_1*10
opr_1=-(opr_1+(tab[i++]-0x30))
n='-'
fu_flag=0
}
}
}
opr_1=0
opr_temp=0
xiabiao=0
xiaoshu=1
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)