1、下个keil3软件,新建工程之后,新建文件,写文件名的时候,写asm后缀的就是写汇编语言,写c后缀的就是写C语言。
2、至于怎么编程,单片机编程,重点就是掌握单片机有哪些I/o口,哪些寄存器,哪些特殊寄存器。
3、推荐看一下视频《十天学会单片机》,搜一下都有的,对初学者非常有帮助。
4、另外补充一点,学单片机,光看书一年都学不会,边看边学,一个月就能入门了,所以最好弄一块板子,在上面跑跑程序。
单片机一旦响应中断请求,就由硬件完成以下功能:
(1)根据响应的中断源的中断优先级,使相应的优先级状态触发器置1;
(2)执行硬件中断服务子程序调用,并把当前程序计数器PC的内容压入堆栈,保护断点,寻找中断源;
(3)清除相应的中断请求标志位(串行口中断请求标志RI和TI除外);
(4)把被响应的中断源所对应的中断服务程序的入口地址(中断矢量)送入PC,从而转入相应的中断服务程序。
(5)中断返回,程序返回断点处继续执行。
扩展资料:
单片机应用分类:
单片机(Microcontrollers)作为计算机发展的一个重要分支领域,根据发展情况,从不同角度,单片机大致可以分为通用型/专用型、总线型/非总线型及工控型/家电型。
通用型:
这是按单片机(Microcontrollers)适用范围来区分的。例如,80C51式通用型单片机,它不是为某种专门用途设计的;专用型单片机是针对一类产品甚至某一个产品设计生产的,例如为了满足电子体温计的要求,在片内集成ADC接口等功能的温度测量控制电路。
总线型:
这是按单片机(Microcontrollers)是否提供并行总线来区分的。总线型单片机普遍设置有并行地址总线、数据总线、控制总线,这些引脚用以扩展并行外围器件都可通过串行口与单片机连接。
另外,许多单片机已把所需要的外围器件及外设接口集成一片内,因此在许多情况下可以不要并行扩展总线,大大减省封装成本和芯片体积,这类单片机称为非总线型单片机。
控制型:
这是按照单片机(Microcontrollers)大致应用的领域进行区分的。一般而言,工控型寻址范围大,运算能力强;用于家电的单片机多为专用型,通常是小封装、低价格,外围器件和外设接口集成度高。显然,上述分类并不是惟一的和严格的。例如,80C51类单片机既是通用型又是总线型,还可以作工控用。
参考资料:
#include<reg51h> //头文件//
#define uchar unsigned char
#define uint unsigned int
#define ulint unsigned long int
uchar tcount,tflag=0;
uchar flag=2;
uchar signtime[8]={0x01,0x07,0x0f,0x00,0x01,0x0f,0x00,0x00};
uchar signdate[8]={0x00,0x09,0x0f,0x00,0x04,0x0f,0x00,0x01};
#define tn0h 0x70
#define tn0l 0x00
#define tn1h 0x70
#define tn1l 0x01
sbit diverout=P2^0;///输出控制电机
//10ms延时//
void delay10ms(void)
{
uchar i=255;
uchar j=255;
while(i>0)
{
j=255;
while(j>0)
j--;
i--;
}
}
//键盘扫描 时间修改//
void keyscan()
{
uchar key=0;
if(P1!=0xff)
{
delay10ms();
delay10ms();
if(P1!=0xff)
{
TR0=0;
if(P1==0x7f)flag++;
if(flag>2)flag=0;
if(P1==0xbf){lcd_init();display();}
if(flag==0)
{
if(P1==0xfe)signtime[0]++;
if(P1==0xfd)signtime[1]++;
if(P1==0xfb)signtime[3]++;
if(P1==0xf7)signtime[4]++;
if(P1==0xef)signtime[6]++;
if(P1==0xdf)signtime[7]++;
if(signtime[0]>2)
signtime[0]=0;
if(signtime[1]>9)
signtime[1]=0;
if(signtime[3]>5)
signtime[3]=0;
if(signtime[4]>9)
signtime[4]=0;
if(signtime[6]>5)
signtime[6]=0;
if(signtime[7]>9)
signtime[7]=0;
if(signtime[0]==2&&signtime[1]==4)
{
signtime[0]=0;
signtime[1]=0;
}
}
if(flag==1)
{
if(P1==0xfe)signdate[0]++;
if(P1==0xfd)signdate[1]++;
if(P1==0xfb)signdate[3]++;
if(P1==0xf7)signdate[4]++;
if(P1==0xef)signdate[6]++;
if(P1==0xdf)signdate[7]++;
if(signdate[0]>9)
signdate[0]=0;
if(signdate[1]>9)
signdate[1]=0;
if(signdate[3]>1)
signdate[3]=0;
if(signdate[4]>9)
signdate[4]=0;
if(signdate[6]>3)
signdate[6]=0;
if(signdate[7]>9)
signdate[7]=0;
if(signdate[3]==1&&signdate[4]==3)
{
signdate[3]=0;
signdate[4]=1;
}
if(signdate[6]==3&&signdate[7]==2)
{
signdate[6]=0;
signdate[7]=1;
}
}
TR0=1;
}
}
}
//时间刷新//
void timechange()
{
signtime[7]+=1;
if(signtime[7]==10)//秒
{
signtime[7]=0;
signtime[6]+=1;
}
if(signtime[6]==6)//秒
{
signtime[6]=0;
signtime[4]+=1;
}
if(signtime[4]==10)//分
{
signtime[4]=0;
signtime[3]+=1;
}
if(signtime[3]==6)//分
{
signtime[3]=0;
signtime[1]+=1;
}
if(signtime[1]==10)//时
{
signtime[1]=0;
signtime[0]+=1;
}
if(signtime[0]==2&&signtime[1]==4)//时
{
signtime[0]=0;
signtime[1]=0;
signdate[7]++;
}
//大月31天
if((signdate[3]==0&&signdate[4]==1)||(signdate[3]==0&&signdate[4]==3)||(signdate[3]==0&&signdate[4]==5)||(signdate[3]==0&&signdate[4]==7)||(signdate[3]==0&&signdate[4]==8)||(signdate[3]==1&&signdate[4]==0)||(signdate[3]==1||signdate[4]==2))
{
if(signdate[7]==10)//日
{
signdate[7]=0;
signdate[6]+=1;
}
if(signdate[6]==3&&signdate[7]==2)//日
{
signdate[6]=0;
signdate[7]=1;
signdate[4]+=1;
}
if(signdate[4]==10)//月
{
signdate[4]=0;
signdate[3]+=1;
}
if(signdate[3]==1&&signdate[4]==2)//月
{
signdate[3]=0;
signdate[4]=1;
signdate[1]+=1;
}
if(signdate[1]==10)//年
{
signdate[1]=0;
signdate[0]+=1;
}
}
//小月30天
if((signdate[3]==0&&signdate[4]==4)||(signdate[3]==0&&signdate[4]==6)||(signdate[3]==0&&signdate[4]==9)||(signdate[3]==1&&signdate[4]==1))
{
if(signdate[7]==10)//日
{
signdate[7]=0;
signdate[6]+=1;
}
if(signdate[6]==3&&signdate[7]==1)//日
{
signdate[6]=0;
signdate[7]=1;
signdate[4]+=1;
}
if(signdate[4]==10)//月
{
signdate[4]=0;
signdate[3]+=1;
}
if(signdate[3]==1&&signdate[4]==3)//月
{
signdate[3]=0;
signdate[4]=1;
signdate[1]++;
}
if(signdate[1]==10)//年
{
signdate[1]=0;
signdate[0]+=1;
}
}
//2月28天
if(signdate[3]==0&&signdate[4]==2)
if(signdate[6]==2&&signdate[7]==9)
{
signdate[7]=1;
signdate[6]=0;
signdate[4]+=1;
}
if(((signtime[0]==0)&&(signtime[1]==9)&&(signtime[3]==0)&&(signtime[4]==0))||((signtime[0]==1)&&(signtime[1]==8)&&(signtime[3]==0)&&(signtime[4]==0)))
diverout=1;
if(((signtime[0]==0)&&(signtime[1]==9)&&(signtime[3]==2)&&(signtime[4]==0))||((signtime[0]==1)&&(signtime[1]==8)&&(signtime[3]==2)&&(signtime[4]==0)))
diverout=0;
}
//一秒定时 50ms扫描键盘//
void t1(void) interrupt 1 using 2
{
TR0=0;
TH0=tn1h;
TL0=tn1l;
TR0=1;
tcount++;
if(tcount==50) //一秒定时
{
tflag=1;
tcount=0;
timechange();
}
keyscan();
}
//主程序//
void main()
{
TMOD=0x01; //定时器工作模式 方式一
TH0=tn0h; //
TL0=tn0l; //
TR0=1; //启动定时器一
ET0=1; //允许定时器0中断
EA=1;
lcd_init();
while(1)
{
;
}
}
MCS-51单片机的存储器编址方式采用与工作寄存器、I/O端口锁存器统一编址的方式。程序存储器和数据存储器空间好似相互独立的,各自有自己的寻址系统和控制信号,物理结构也不同。程序存储器为只读存储器(ROM),数据存储器为随机存储器(RAM)。\x0d\ 1、程序存储器常用来存放程序和表格常数。程序存储器以程序计数器PC作为地址指针,通过16位地址总线,可寻址的地址空间为64K,片内、片外统一编址。在程序存储器中有些特殊的单元在使用时应加以注意。其中一组特殊的单元是0000H~0002H单元,在系统复位之后,PC为0000H,单片机从0000H开始执行程序,该单元是系统执行陈故乡的起始地址,通常在该地址中存放一条跳转指令,而用户程序从跳转地址开始存放程序。另外一组特殊单元为0003H~0021AH,这40个单元被均匀的分为5份,其定义如下:\x0d\0003H~000AH:外部中断0的中断地址区\x0d\000BH~0012H:定时器/计数器0的中断地址区\x0d\0013H~001AH:外部中断1的中断地址区\x0d\001BH~0022H:定时器/计数器1的中断地址区\x0d\0023H~002AH:串行中断地址区\x0d\可见以上40个单元是专门用于存放中断处理程序的地址单元,中断响应后,按中断的类型自动转到各自的终端区去执行程序。从上面看出,每个终端服务程序只有8个字节单元,用8个字节来存放一个中断服务程序显然是不可能的。通常情况下好似在中断响应的地址区存放一条无条件转移指令,指向程序存储器的真正存放终端服务程序的空间去执行。\x0d\ 2、MCS-51单片机的数据存储器无论在物理上或者逻辑上都是分为两个地址空间,一个为内部数据存储器,访问内部数据存储器用MOV指令;另外一个为外部数据存储器,访问外部数据存储器用MOVX指令。8051内部有128个8位数据存储单元和128个专用寄存器单元,这些单元是统一编址的,专用寄存器只能用于存放控制指令数据。所以,用户能使用的RAM只有00H~7FH单元组成的128字节地址空间,可以存放读写的数据或者运算的中间结果;80H~FFH单元组成的高128字节地址空间的特殊功能寄存器(SFR)区,只能访问,而不能用于存放用户数据。片内RAM的低128字节还可以分成工作寄存器区,可位寻址区和一般RAM去3个区域。
访问外部ram,必须使用movx指令,用16位地址访问外部ram,必须使用dptr寻址,这是第一个要点。
movx @dptr, a 这条指令的寻址方式是固定的,必须使用a,这是第二个要点。
所以想清除内存区域,必须是
clr a
movx @dptr, a
其中dptr 的内容需要连续变化,你的程序里面少了 inc dptr 这一句。
剩下的问题 mov r0, a 和 mov a, r0 的意思无外乎是个简单的保存、恢复a内容的 *** 作。
其实这里用a来控制循环次数不是很理想,随便用一个寄存器就可以做。
mov dptr , #7000h
mov r7, #0 ; 本意是r7 = 256,清除 256字节
clr a
loop:
movx @dptr, a ; a 的内容始终是0
inc dptr ; 原来的程序缺少这一句,很关键
djnz r7, loop
ret
ORG 0000H ;程序执行开始地址
LJMP START ;跳到标号START执行
ORG 0003H ;外中断0中断程序入口
LJMP REMO ;外中断0中断返回
ORG 000BH ;定时器T0中断程序入口
LJMP TIME0 ;跳至INTTO执行
ORG 0013H ;外中断1中断程序入口
RETI ;外中断1中断返回
ORG 001BH ;定时器T1中断程序入口
LJMP TIME1 ;跳至TIME1执行
ORG 0023H ;串行中断程序入口地址
RETI ;串行中断程序返回
;
TIME1: RETI
;
TIMEADD EQU 30H;30H做为软件计数缓存
DISP1 EQU 31H;31H做为第一位显示缓存
DISP2 EQU 32H;32H做为第二位显示缓存
DISP3 EQU 33H;33H做为第三位显示缓存
DISP4 EQU 34H;34H做为第四位显示缓存
SECLED EQU P10;秒点显示P10
HALFSEC EQU 35H;半秒计数缓存
UPKEY BIT P27;定义P27是UP键
SETKEY BIT P20;定义P20是SET键
BUZZ BIT P25;
;
;第1位使能P21
;第2位使能P22
;第3位使能P23
;第4位使能P24
;
ORG 0030H;
;
START:
MOV SP,#5FH;放堆栈
MOV P2,#0FFH;把P2置高
CLR P25;把p25置0
LCALL BUZZER;发出滴声
LCALL BUZZER;按键滴声
MOV TIMEADD,#0;软件计数器清零
MOV TMOD,#11H;TIME0工作于方式1,TIME1工作于方式1
MOV TH0,#3CH;
MOV TL0,#0B0H;放定时预置数15536
MOV IE,#8BH;开INT0,TIME0,TIME1
MOV IP,#02H;TIME0中断优先
SETB IT0;外部中断0为负跳变方式触发
SETB TR0;开始计数
MOV DISP1,#00H;
MOV DISP2,#00H;
MOV DISP3,#00H;
MOV DISP4,#00H;把所有显示缓存清零
MOV HALFSEC,#00H;把半秒计数缓存清零
MOV DPTR,#TAB;
SCAN:
MOV A,DISP1;把第一位显示缓存送入A
MOVC A,@A+DPTR;查表
SETB P24;
CLR P21;第一位显示使能
MOV P0,A;查表得到的7段码送给P0去显示
LCALL DELAY;延时
MOV P0,#0FFH;显示一小段时间后关掉7段显示,去显示下一位
MOV A,DISP2;
MOVC A,@A+DPTR;
SETB P21;
CLR P22;
MOV P0,A;
LCALL DELAY;
MOV P0,#0FFH;
MOV A,DISP3;
MOVC A,@A+DPTR;
SETB P22;
CLR P23;
MOV P0,A;
LCALL DELAY;
MOV P0,#0FFH;
MOV A,DISP4;
MOVC A,@A+DPTR;
SETB P23;
CLR P24;
MOV P0,A;
LCALL DELAY;
MOV P0,#0FFH;
JNB SETKEY,ADJUST;按键按下时去调整时间
;以下是进位程序
MOV A,DISP1;把第一位缓存送入A
CJNE A,#10,SCAN;如果第一位不等于10继续扫描
MOV DISP1,#00H;如果第一位等于10了就把第一位清零
INC DISP2;第二位加1
MOV A,DISP2;
CJNE A,#6,SCAN;如果第二位不等于6继续扫描
MOV DISP2,#00H;
INC DISP3;
MOV A,DISP4;
CJNE A,#2,PM;
MOV A,DISP3;
CJNE A,#4,SCAN;
MOV DISP3,#00H;
AJMP DIS4;
PM:
MOV A,DISP3;
CJNE A,#10,SCAN;
MOV DISP3,#00H;
DIS4:
INC DISP4;
MOV A,DISP4;
CJNE A,#3,SCAN;
MOV DISP4,#00H;
AJMP SCAN;
;
DELAY: ;延时子程序
MOV R7,#2
NOP
D1: MOV R6,#2
DJNZ R6,$
DJNZ R7,D1
RET
;
TAB: DB 88H,0EBH,91H,0A1H,0E2H,0A4H,84H,0E9H,80H,0A0H,0C0H,86H,9CH,83H,94H,0D4H,0FFH
;
;
;
;
;下面程序为设置时间用
ADJUST:
LCALL ADJDELAY;
JB SETKEY,SET1;
LCALL BUZZER;按键滴声
JNB SETKEY,$
CLR TR0; 暂时关闭计时
ADJ4:
SETB P21;
CLR P24;
MOV A,DISP4;
MOVC A,@A+DPTR;
MOV P0,A;显示第四位
JNB SETKEY,ADJ8;如果设置键有动作去调节第3位
JB UPKEY,ADJ4;加键是否按下
LCALL ADJDELAY;
JB UPKEY,ADJ4;延时后再检查加键是否按下
LCALL BUZZER;按键滴声
JNB UPKEY,$;等待加键松开
INC DISP4;第四位加1
MOV A,DISP4;
CJNE A,#3,ADJ4;第四位不等于3转移
MOV DISP4,#00H;第四位等于3清零
AJMP ADJ4;再去显示第四位
ADJ8:
LCALL ADJDELAY;
JB SETKEY,ADJ4;
LCALL BUZZER;按键滴声
JNB SETKEY,$;
ADJ3:
SETB P24;
CLR P23;
MOV A,DISP3;
MOVC A,@A+DPTR;
MOV P0,A;显示第三位
JNB SETKEY,ADJ7;
JB UPKEY,ADJ3;
LCALL ADJDELAY;
JB UPKEY,ADJ3;
LCALL BUZZER;按键滴声
JNB UPKEY,$;
INC DISP3;第3位加1
MOV A,DISP4;
CJNE A,#2,PM1;
MOV A,DISP3;
CJNE A,#4,ADJ3;第3位不等于4转移
MOV DISP3,#00H;第四位等于3清零
AJMP ADJ3;再去显示第四位
PM1:
MOV A,DISP3;
CJNE A,#10,ADJ3;
MOV DISP3,#00H;
AJMP ADJ3;
SET1:
LCALL BUZZER;按键滴声
LCALL BUZZER;按键滴声
JNB SETKEY,$;
NOP;
MOV HALFSEC,#00H;清零秒针
SETB TR0;
LJMP SCAN;
ADJ7:
LCALL ADJDELAY;
JB SETKEY,ADJ3;
LCALL BUZZER;按键滴声
JNB SETKEY,$;
ADJ2:
SETB P23;
CLR P22;
MOV A,DISP2;
MOVC A,@A+DPTR;
MOV P0,A;显示第二位
JNB SETKEY,ADJ6;
JB UPKEY,ADJ2;
LCALL ADJDELAY;
JB UPKEY,ADJ2;
LCALL BUZZER;按键滴声
JNB UPKEY,$;
INC DISP2;第2位加1
MOV A,DISP2;
CJNE A,#6,ADJ2;第2位不等于6转移
MOV DISP2,#00H;第2位等于6清零
AJMP ADJ2;再去显示第2位
ADJ6:
LCALL ADJDELAY;
JB SETKEY,ADJ2;
LCALL BUZZER;按键滴声
JNB SETKEY,$;
ADJ1:
SETB P22;
CLR P21;
MOV A,DISP1;
MOVC A,@A+DPTR;
MOV P0,A;显示第一位
JNB SETKEY,ADJ5;如果SET键有动作转去抖
JB UPKEY,ADJ1;
LCALL ADJDELAY;
JB UPKEY,ADJ1;
LCALL BUZZER;按键滴声
JNB UPKEY,$;
INC DISP1;第1位加1
MOV A,DISP1;
CJNE A,#10,ADJ1;第1位不等于10转移
MOV DISP1,#00H;第1位等于10清零
AJMP ADJ1;再去显示第1位
ADJ5:
LCALL ADJDELAY;
JB SETKEY,ADJ1;
AJMP SET1;
ADJDELAY:;是不是延时40MS
MOV R7,#200
D3: MOV R6,#100
DJNZ R6,$
DJNZ R7,D3
RET
BUZZER: MOV R6,255;蜂鸣子程序
BUZZ1: CPL BUZZ;
MOV R7,#80;
DJNZ R7,$;
DJNZ R6,BUZZ1;
CLR BUZZ;
RET
;以上为设置时间用
;
REMO:
RETI;
;
;
;
TIME0:; TIME0中断处理程序
MOV TH0,#3CH;
MOV TL0,#0B6H;重新放定时预置数15542,用预置数较正时间。
PUSH ACC;机器周期2
PUSH PSW;机器周期2
INC TIMEADD;软件计数器加1,机器周期1
MOV A,TIMEADD;加1后送给A,机器周期1
CJNE A,#10,T_RET;如果A不等于10跳到T_RET,机器周期2
CPL SECLED;取反秒点LED,软件计数器计时半秒,机器周期1
MOV TIMEADD,#00H;软件计数器清零,机器周期1
INC HALFSEC;秒加1,机器周期1
MOV A,HALFSEC;机器周期1
CJNE A,#120,T_RET;把秒针缓存和120比较,不等跳转T_RET,机器周期2
INC DISP1;第一位显示加1,机器周期1
MOV HALFSEC,#00H;清零秒针,机器周期1
T_RET:
POP PSW
POP ACC
RETI
END
以上就是关于单片机8051怎么编程全部的内容,包括:单片机8051怎么编程、简述8051单片机中断响应过程、8051单片机定时程序等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)