部分程序代码:
#include "C8051F020h" //包含C8051F020硬件信息的头文件
#include "absacch" //包含绝对地址访问信息的头文件
#include"mathh"
sbit LCD_EP=P2^4;
sbit LCD_RW=P2^2;
sbit LCD_RS=P2^0;
#define LCD_Data_BUS_Out P7
#define LCD_Data_BUS_In P7
#define key P5
unsigned char keyval;
int i;
typedef unsigned int uint;
code unsigned char LCD_InitialCode[]=;
unsigned char temp;
void Reset_Sources_Init() //禁止看门
{
WDTCN = 0xDE;
WDTCN = 0xAD;
}
void Port_IO_Init() //交叉开关配置
{
//P74OUT = 0xC0; //p7推挽
P2MDOUT = 0xff; //p2推挽
XBR0 = 0x00;
XBR1 = 0x00;
XBR2 = 0x40; //交叉开关使能
}
void Oscillator_Init() //振荡器初始化,使用片外晶体振荡器
{
uint i = 0;
OSCXCN = 0x67; //使用片外晶体谐振器,f>67MHz
for (i = 0; i < 3000; i++); //Wait 1ms for initialization
while ((OSCXCN & 0x80) == 0); //检测外部振荡器是否有效
OSCICN = 0x08; //选择外部振荡器作为系统时钟,禁止内部时钟
}
//定时器1初始化函数,定时器1作为波特率发生器
void Timer_Init()
{
CKCON = 0x10; //C/T1直接使用系统时钟作为时钟源
TCON = 0x40; //C/T1允许
TMOD = 0x20; //C/T1方式2(8位重装填计数)
TL1 = 0xFA; //C/T1波特率115200计数值
TH1 = 0xFA;
}
void Init_Device() // 设备初始化函数,在主程序中调用Init_Device()
{
Reset_Sources_Init(); //复位源初始化
Port_IO_Init(); //端口初始化
Oscillator_Init(); //时钟源初始化
Timer_Init(); //定时器1初始化
}
有东西就发出来分享啊,我就直接写下面了。
ORG 0000H
SJMP MAIN
ORG 0030H
MAIN :
MOV SP,#60H
MOV P0,#0FFH
MOV P1,#0FFH
MOV P2,#0FFH
MOV P3,#0FFH
MOV R2,#00H
MOV R3,#00
MOV R4,#00
MOV B,#00H
MOV 33H,#00H;十位
MOV 34H,#00H;个位
MOV 35H,#00H;高四位
KEYCODE EQU 35H
S0: LCALL PRESSKEY ;长调用有无按键按下
S1: LCALL DISPLAY ;长调用数字处理程序段
LJMP S0 ;返回S0
; 有无按键按下
PRESSKEY:
MOV P1,#0F0H
MOV A,P1
CJNE A,#0F0H,D2
LJMP D5
D2: LCALL DELAY10MS
MOV A,P1
CJNE A,#0F0H,KEYVALUE
LJMP D5
;按键键值判断
KEYVALUE:MOV 33H,#00H
mov 34H,#00H
MOV P1,#0F0H
MOV A,P1
ANL A,#0F0H ;ANL与 *** 作
MOV B,A
MOV P1,#0FH
MOV A,P1
ANL A,#0FH ;ANL与 *** 作
ORL A,B ;ORL或 *** 作
MOV KEYCODE,A
MOV R3,#00
D4: MOV A,R3
MOV DPTR,#TABBLE2
MOVC A,@A+DPTR
CJNE A,KEYCODE,D3
MOV A,R3
MOV R2,A
LJMP D5
D3: INC R3
LJMP D4
D5: RET
;数字处理程序段
DISPLAY:
MOV A,R2
CJNE A,#10,CMP1
CMP1: JC LOOP2
LJMP LOOP3
LOOP2: MOV A, R2
MOV 34H,A
LJMP DISPLAY1
LOOP3: MOV B,#10
DIV AB
MOV 33H,A
MOV A,B
MOV 34H,A
LJMP DISPLAY1
;显示程序段
DISPLAY1:
MOV DPTR,#TABBLE1
MOV A,34H
MOVC A,@A+DPTR
MOV P2,#07FH
MOV P0,A
ACALL DELAY5MS
MOV DPTR,#TABBLE1
MOV A,33H
MOVC A,@A+DPTR
MOV P2,#0BFH
MOV P0,A
ACALL DELAY5MS
RET ;子程序返回
;
DELAY:
;延时子程序
MOV R5,#100
DELAY0: LCALL DELAY10MS
DJNZ R5,DELAY0
LJMP HUJK
DELAY10MS:MOV R4,#2
DELAY2 : LCALL DELAY5MS
DJNZ R4,DELAY2
LJMP HUJK
DELAY5MS:
MOV R6,#25
DELAY1:
MOV R7,#100
DJNZ R7,$
DJNZ R6,DELAY1
HUJK : RET ;子程序返回
;
TABBLE1:
DB 0C0H,0F9H,0A4H,0B0H,99H,92H,82H,0F8H,80H,90H,08H
;
TABBLE2:
DB 0EBH,77H,7BH,7DH,0B7H,0BBH,0BDH,0D7H,0DBH,0DDH,7EH,0BEH,0DEH,0EEH,0E7H,0EDH,0FFH
;
END
给你举个例子吧:
假设20H原本保存的数是48h(BCD码,代表十进制的48),
除以10H之后,A中保存的是04h,B中保存的是08h。加上30h并分别放在21H、22H中,结果分别是34h('4'的ASCII码)、38h('8'的ASCII码)。
“BCD和ASCII之间不是差30H么”
在0~9之内的一位数字是如此。问题是20H中的是个两位数,所以要除以10H将十位与个位分离开。
另外吐槽一下:这题目用除法来分离十位个位是效率低下的行为……
EEPROM是“Eleally Eras-able Programmable Read-only”(电可擦写可编程只读)的缩写,EEPROM在正常情况下和EPROM-样,可以在掉电的情况下保存数据,所不同的是,它在特定引脚上施加特定或使用特定的总线擦写命令就可以在在线的情况下方便地完成数据的擦除和写入,这个特点使EEPROM被用于广阔的消费领域,如汽车、电信、医疗、工业和个人计算机相关的市场,主要用于存储个人数据和配置/调整数据
。EEPROM又分并行EEPROM和串行EEPROM,并行EEPROM器件虽然有很快的读写速度,但要使用很多引脚,电行EEPROM器件功能上和并行EEPROM基本相同,却可以提供更少的引脚数、更小的封装、更低的电压和更低的功耗,是现在使用的非易失性存储器中灵活性最高的类型。串行EEPROM按总线分,常用的有I2C、SPI、Microwire总线。本文将介绍这三种总线连接的编程方法。
阳总线I2C总线(Inter Integrated Circuit内部总线)是两线式串行总线,仅需要时钟和数据两根线就可以进行数据传输,仅需要占用的2个I/O引脚,使用时十分方便。I2C总线还可以在同一总线上挂多个器件,每个器件可以有自己的器件地址,读写 *** 作时需要先发送器件地址,该地址的器件得到确认后便执行相应的 *** 作,而在同一总线上的其他器件不做响应,称之为器件寻址,这个原理就与我们打电话的原理相当。
I2C总线产生于上世纪80年代,由PHILIPS公司开发,早期多用于音频和视频设备,如今I2C总线的器件和设备已多不胜数。最常见的采用I2C总线的EEPROM也已被广泛使用于各种家电、工业及通信设备中,主要用于保存设备所需要的配置数据、采集数据及程序等,如电视机中用于保存频道信息,电脑内存条中保存内存大小等相关信息,汽车里用于保存里程信息等。生产FC总线EEPROM的厂商很多,如ATMEL、Micro公司,它们都是以24来开头命名芯片型号,最常用的是24C系列。24C系列从24C01到24C512,C后面的数字代表该型号的芯片有多少K的存储位。如ATMEL的24C64,存储位是64K位,也就是说可以存储8K(8192)字节,它支持18V~5V,可以擦写1百万次,数据可以保持100年,使用5V电源时时钟可以达到400k,并且有多种封装可供选择。图1就是ATMEL24C64芯片的PID封装和用于内存条SPD(Serial Presence Detect)上的24芯片。
/这是用LCD显示所测温度的代码,你参考一下,如果没问题的话,其他的功能你再添加就好了,不难/
#include<reg52h>
#include<intrinsh>
#define uint unsigned int
#define uchar unsigned char
#define Nack_number 10
//端口定义
uchar flag; //LCD控制线接口
sbit RS=P1^0; //RS端
sbit RW=P1^1; //读写端
sbit LCDE=P2^5; //使能端
//mlx90614端口定义
sbit SCK=P2^1; //时钟线
sbit SDA=P2^2; //数据线
//数据定义
bdata uchar flag1; //可位寻址数据
sbit bit_out=flag1^7;
sbit bit_in=flag1^0;
uchar tempH,tempL,err;
// LCD1602
//向LCD写入命令或数据
#define LCD_COMMAND 0 //命令
#define LCD_DATA 1 // 数据
#define LCD_CLEAR_SCREEN 0x01 // 清屏
#define LCD_HOMING 0x02 // 光标返回原点
//设置显示模式 0x08+
#define LCD_SHOW 0x04 //显示开
#define LCD_HIDE 0x00 //显示关
#define LCD_CURSOR 0x02 //显示光标
#define LCD_NO_CURSOR 0x00 //无光标
#define LCD_FLASH 0x01 //光标闪动
#define LCD_NO_FLASH 0x00 //光标不闪动
//设置输入模式 0x04+
#define LCD_AC_UP 0x02 //光标右移 AC+
#define LCD_AC_DOWN 0x00 //默认 光标左移 AC-
#define LCD_MOVE 0x01 //画面可平移
#define LCD_NO_MOVE 0x00 //默认 画面不移动
// mlx90614
//command mode 命令模式
#define RamAccess 0x00 //对RAM *** 作
#define EepomAccess 0x20 //对EEPRAM *** 作
#define Mode 0x60 //进入命令模式
#define ExitMode 0x61 //退出命令模式
#define ReadFlag 0xf0 //读标志
#define EnterSleep 0xff //进入睡眠模式
//ram address read only RAM地址(只读)
#define AbmientTempAddr 0x03 //周围温度
#define IR1Addr 0x04
#define IR2Addr 0x05
#define LineAbmientTempAddr 0x06 //环境温度
/0x0000 0x4074 16500 001/单元
-40 125/
#define LineObj1TempAddr 0x07 //目标温度,红外温度
/0x27ad-0x7fff 0x3559 22610 002/单元
-7001-38219 001 4522/
#define LineObj2TempAddr 0x08
//eepom address EEPROM地址
#define TObjMaxAddr 0x00 //测量范围上限设定
#define TObjMinAddr 0x01 //测量范围下限设定
#define PWMCtrlAddr 0x02 //PWM设定
#define TaRangeAddr 0x03 //环境温度设定
#define KeAddr 0x04 //频率修正系数
#define ConfigAddr 0x05 //配置寄存器
#define SMbusAddr 0x0e //器件地址设定
#define Reserverd1Addr 0x0f //保留
#define Reserverd2Addr 0x19 //保留
#define ID1Addr 0x1c //ID地址1
#define ID2Addr 0x1d //ID地址2
#define ID3Addr 0x1e //ID地址3
#define ID4Addr 0x1f //ID地址4
//函数声明
void start(); //MLX90614发起始位子程序
void stop(); //MLX90614发结束位子程序
uchar ReadByte(void); //MLX90614接收字节子程序
void send_bit(void); //MLX90614发送位子程序
void SendByte(uchar number); //MLX90614接收字节子程序
void read_bit(void); //MLX90614接收位子程序
void delay(uint N); //延时程序
uint readtemp(void); //读温度数据
void init1602(void); //LCD初始化子程序
void busy(void); //LCD判断忙子程序
void cmd_wrt(uchar cmd); //LCD写命令子程序
void dat_wrt(uchar dat); //LCD写数据子程序
void display(uint Tem); //显示子程序
void Print(uchar str); //字符串显示程序
//主函数
void main()
{
uint Tem; //温度变量
SCK=1;
SDA=1;
delay(4);
SCK=0;
delay(1000);
SCK=1;
init1602(); //初始化LCD
while(1)
{
Tem=readtemp(); //读取温度
cmd_wrt(0x01); //清屏
Print(" Temperature: "); //显示字符串 Temperature: 且换行
display(Tem); //显示温度
Print(" ^C"); //显示摄氏度
delay(10000); //延时再读取温度显示
}
}
void Print(uchar str) //字符串显示程序
{
while(str!='\0') //直到字符串结束
{
dat_wrt(str); //转成ASCII码
str++; //指向下一个字符
}
}
//输入转换并显示
void display(uint Tem)
{
uint T,a,b;
T=Tem2;
if(T>=27315) //温度为正
{
T=T-27315; //
a=T/100; //温度整数
b=T-a100; //温度小数
if(a>=100) //温度超过100度
{
dat_wrt(0x30+a/100); //显示温度百位
dat_wrt(0x30+a%100/10); //显示温度十位
dat_wrt(0x30+a%10); //显示温度个位
}
else if(a>=10) //温度超过10度
{
dat_wrt(0x30+a%100/10); //显示温度十位
dat_wrt(0x30+a%10); //显示温度个位
}
else //温度不超过10度
{
dat_wrt(0x30+a); //显示温度个位
}
dat_wrt(0x2e); //显示小数点
if(b>=10) //温度小数点后第1位数不等于0
{
dat_wrt(0x30+b/10); //显示温度小数点后第1位数
dat_wrt(0x30+b%10); //显示温度小数点后第2位数
}
else //温度小数点后第1位数等于0
{
dat_wrt(0x30); //显示温度小数点后第1位数0
dat_wrt(0x30+b); //显示温度小数点后第2位数
}
}
else //温度为负
{
T=27315-T;
a=T/100;
b=T-a100;
dat_wrt(0x2d); //显示负号
if(a>=10) //温度低于负10度
{
dat_wrt(0x30+a/10); //显示温度十位
dat_wrt(0x30+a%10); //显示温度个位
}
else //温度高于负10度
{
dat_wrt(0x30+a); //显示温度个位
}
dat_wrt(0x2e); //显示小数点
if(b>=10) //温度小数点后第1位数不等于0
{
dat_wrt(0x30+b/10); //显示温度小数点后第1位数
dat_wrt(0x30+b%10); //显示温度小数点后第2位数
}
else //温度小数点后第1位数等于0
{
dat_wrt(0x30); //显示温度小数点后第1位数0
dat_wrt(0x30+b); //显示温度小数点后第2位数
}
}
}
//
void start(void) //停止条件是 SCK=1时,SDA由1到0
{
SDA=1;
delay(4);
SCK=1;
delay(4);
SDA=0;
delay(4);
SCK=0;
delay(4);
}
//------------------------------
void stop(void) //停止条件是 SCK=1时,SDA由0到1
{
SCK=0;
delay(4);
SDA=0;
delay(4);
SCK=1;
delay(4);
SDA=1;
}
//---------发送一个字节---------
void SendByte(uchar number)
{
uchar i,n,dat;
n=Nack_number; //可以重发次数
Send_again:
dat=number;
for(i=0;i<8;i++) //8位依次发送
{
if(dat&0x80) //取最高位
{
bit_out=1; //发1
}
else
{
bit_out=0; //发0
}
send_bit(); //发送一个位
dat=dat<<1; //左移一位
}
read_bit(); //接收1位 应答信号
if(bit_in==1) //无应答时重发
{
stop();
if(n!=0)
{
n--; //可以重发Nack_number=10次
goto Repeat; //重发
}
else
{
goto exit; //退出
}
}
else
{
goto exit;
}
Repeat:
start(); //重新开始
goto Send_again; //重发
exit: ; //退出
}
//-----------发送一个位---------
void send_bit(void)
{
if(bit_out==1)
{
SDA=1; //发1
}
else
{
SDA=0; //发0
}
_nop_();
SCK=1; //上升沿
delay(4);delay(4);
SCK=0;
delay(4);delay(4);
}
//----------接收一个字节--------
uchar ReadByte(void)
{
uchar i,dat;
dat=0; //初值为0
for(i=0;i<8;i++)
{
dat=dat<<1; //左移
read_bit(); //接收一位
if(bit_in==1)
{
dat=dat+1; //为1时对应位加1
}
}
SDA=0; //发送应答信号0
send_bit();
return dat; //带回接收数据
}
//----------接收一个位----------
void read_bit(void)
{
SDA=1; //数据端先置1
bit_in=1;
SCK=1; //上升沿
delay(4);delay(4);
bit_in=SDA; //读数据
_nop_();
SCK=0;
delay(4);delay(4);
}
//------------------------------
uint readtemp(void)
{
SCK=0;
start(); //开始条件
SendByte(0x00); //发送从地址00
SendByte(0x07); //发送命令
start(); //开始条件
SendByte(0x01); //读从地址00
bit_out=0;
tempL=ReadByte(); //读数据低字节
bit_out=0;
tempH=ReadByte(); //读数据高字节
bit_out=1;
err=ReadByte(); //读错误信息码
stop(); //停止条件
return(tempH256+tempL);
}
//LCD显示子函数
void init1602(void) //初始化LCD
{
cmd_wrt(0x01); //清屏
cmd_wrt(0x0c); //开显示,不显示光标,不闪烁
cmd_wrt(0x06); //完成一个字符码传送后,光标左移,显示不发生移位
cmd_wrt(0x38); //16×2显示,5×7点阵,8位数据接口
}
void busy(void) //LCD忙标志判断
{
flag=0x80; //赋初值 高位为1 禁止
while(flag&0x80) //读写 *** 作使能位禁止时等待 继续检测
{
P0=0xff;
RS=0; //指向地址计数器
RW=1; //读
LCDE=1; //信号下降沿有效
flag=P0; //读状态位 高位为状态
LCDE=0;
}
}
void cmd_wrt(uchar cmd) //写命令子函数
{
LCDE=0;
busy(); //检测 读写 *** 作使能吗
P0=cmd; //命令
RS=0; //指向命令计数器
RW=0; //写
LCDE=1; //高电平有效
LCDE=0;
}
void dat_wrt(uchar dat) //写数据子函数
{
busy(); //检测 读写 *** 作使能吗
LCDE=0;
if(flag==16)
{
RS=0; //指向指令寄存器
RW=0; //写
P0=0XC0; //指向第二行
LCDE=1; //高电平有效
LCDE=0;
}
RS=1; //指向数据寄存器
RW=0; //写
P0=dat; //写数据
LCDE=1; //高电平有效
LCDE=0;
}
//------------延时--------------
void delay(uint n)
{
uint j;
for(j=0;j<n;j++)
{
_nop_();
}
}
CNTA EQU 30H ;8x8 LED阵列行选通顺序计数器,有效值范围0~7
COUNT EQU 31H ;8x8 LED阵列顺序显示计数器,有效值范围0~2
ORG 00H
LJMP START ;跳转到30H开始的主程序主体,避开中断入口地址
ORG 0BH
LJMP T0X ;跳转到定时中断0中断服务程序
ORG 30H
START: MOV CNTA,#00H ;主程序开始
MOV COUNT,#00H ;3个8X8 LED点阵送显示计数
MOV TMOD,#01H ;定时器0设定为定时方式,方式1,16位模式
MOV TH0,#(65536-1000) / 256 ;1ms定时中断预装值高8位
MOV TL0,#(65536-1000) MOD 256 ;1ms定时中断预装值高8位
SETB TR0 ;启动定时器0
SETB ET0 ;允许定时器0中断
SETB EA ;开启总中断允许
WT: JB P20,WT ;读P20端口状态,高电平则原地循环等待其变为低电平
MOV R6,#5 ;P20为低电平,则开始延时滤波循环
MOV R7,#248
D1: DJNZ R7,$
DJNZ R6,D1
JB P20,WT ;再次确认P20是否低电平,不是则认为端口干扰,回到WT继续等待
INC COUNT ;LED阵列计数+1,显示下一个LED阵列
MOV A,COUNT
CJNE A,#03H,NEXT ;LED阵列计数未到3,跳转到NEXT
MOV COUNT,#00H ;LED阵列计数则清零,跳回WT从第一个开始扫描
NEXT: JNB P20,$ ;原地循环,等待P20恢复高电平
SJMP WT ;P20恢复高电平,返回WT,等待下一次动作
T0X: NOP
MOV TH0,#(65536-1000) / 256 ;重装定时计数寄存器
MOV TL0,#(65536-1000) MOD 256
MOV DPTR,#TAB ;设定选通端口查表起始地址
MOV A,CNTA ;得到LED显示行计数值,该计数为1-8,到8时清零重新开始
MOVC A,@A+DPTR ;查表得到行选通端口状态字符
MOV P3,A ;将选通信号送到P3口,低电平的端口指向的LED阵列被选通
MOV DPTR,#GRAPH ;设定显示信息查表起始地址
MOV A,COUNT ;根据计数器,确定当前显示的是1、2、3中的哪个阵列
MOV B,#8
MUL AB ;8X8阵列,所以一个阵列显示信息需要8个字节,
ADD A,CNTA ;指向待显示行的点阵信息
MOVC A,@A+DPTR ;读取
MOV P1,A ;该行8列的显示信息送P1口
INC CNTA ;计数器+1指向下一行
MOV A,CNTA
CJNE A,#8,NEX ;判断是否已到第8行,未到则直接退出中断
MOV CNTA,#00H ;已到,计数清零,下次从第一行开始扫描
NEX: RETI
TAB: DB 0FEH,0FDH,0FBH,0F7H,0EFH,0DFH,0BFH,07FH ;LED阵列行选通端口控制状态值
GRAPH: DB 12H,14H,3CH,48H,3CH,14H,12H,00H ;第1个LED阵列的点阵信息
DB 00H,00H,38H,44H,44H,44H,38H,00H ;第2个LED阵列的点阵信息
DB 30H,48H,44H,22H,44H,48H,30H,00H ;第3个LED阵列的点阵信息
END
以上就是关于一单片机程序问题全部的内容,包括:一单片机程序问题、单片机编程问题、单片机eeprom1ab是什么意思等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)