前边,我讲完了 51单片机 的 寻址方式 和 指令系统,以及几个传统8051都有的基本内部资源(所谓传统8051,或者51单片机,在大多数情况下,请当它们是一回事。)
现在我们来讲一下,我们实际如何写程序,因为只是举例,而且篇幅关系,我们只写一个很简单的小程序,写它们,的一个重要目的是 提供一个很基本的程序模板,让你知道它大致上包含了什么东西,你可以把它当成一个入门例程。
我选择 定时器翻转LED为例,先 汇编,再 C51,都是我自己写的,跑过了,肯定能用。
汇编版本
晕!发现自己以前的都没保存好,只好现写一个,于是只能保证编译无误,至于实际效果如何,因为板子不在手上,也不好说。这部分程序里,有几个使用伪指令的地方在本程序中是没用的,写出来是为了说明这几个最常用的伪指令的功能
//这个程序,只是使用了定时器和中断功能做延时。
LED BIT P1.4; //位定义,从此,LED就表示P1.4这个IO位
COUNT EQU 14H; //这个东西定义一个宏,COUNT表示一个数
//字14H,注意和下边的DATA区分
TEMP DATA 14H; //这两句话功能相似,只是DATA的作用是,
//它是把RAM内的一个地址赋值给一个宏,
//而EQU则是把一个寄存器或者一个直接数赋
//值给一个宏
ORG 0000H //伪指令,ORG表明给接下去的第一条指令指
//定一个ROM里的位置,在程序里,ORG安排
//的地址可以是不按照从小到大排列的。
JMP MAIN; //由于下边有一段中断向量入口,因此,开始
//的空间实际只有3B,这是不可能完成什么工作的,
//因此,我们常在此安排一条转移指令,转移到真正
//程序开始的地方。
ORG 001BH //这就是中断向量入口,中断发生时,首先会来到相
//应的入口,这是定时器1的入口地址001BH
JMP BRT1;
ORG 0100H //如前所述,真正开始执行程序的地方往往在后面,起始
//地址看中断入口的多寡和安排,还有整个单片机ROM的大小
MAIN: MOV TMOD,#10H;
MOV TH1,#3CH; //事实上,在汇编里,有一个更方便的定时初值赋值方法
MOV TL1,#0B0H; //MOV TH1,#HIGH(15535);MOV TL1,#LOW(15535);自动
//取高低8位。更常用的做法是,15535 EQU TIMER
MOV IE,#88H;
SETB TR1;
MOV R0,#14H;
SJMP $;
TAB: DB 03H,34H,53H,
43H,34H,43H; //这个也是伪指令 ,DB表明从TAB标识的
//ROM地址开始,依次存储下边的几个数据
//======================================================================================//
下边是这个程序的C51版本:
#include <REG51.H> //标准51系列单片机的通用头文件
#define COUNT 0x3CAF
//定义区//
sbit output = P0^7; //这里出现了几个C51对ANSI C的扩展关键字,其中sbit相当于伪指令BIT
sfr P1M0 = 0x91; //这个程序,当时是用STC12C2051写的,这两个是扩展的寄存器,于是
sfr P1M1 = 0x92; //sfr这个就相当于 二分之一的EQU,可以用来定义寄存器,另有一个sfr16,
//前者8位寄存器,或者16位寄存器
//子函数声明//
void timer0_initial(void);
void main(void)
{
//初始化定时器//
timer0_initial();
while(1);
}
void timer0_initial(void)
{
IE = 0X82;
TL0 = COUNT % 256; //这是很常见的,但由于经常要重装定时器初值,而C语言里的除法取模运算很耗时间,
TH0 = COUNT / 256; //又为了灵活改变,所以才做成了宏,另一种方法是直接在宏里完成运算
//#define COUNT 500 #define HIGH (65535 - COUNT) / 256.... LOW类似
TMOD = 0X01;
TR0 = 0x01;
}
//关于C51的中断函数写法,简单提几个要点://1 不能带形参,也不能有返回值
//用interrupt x指定使用的中断向量,0到4对应以前的0003 000B ,,,
//C51里,会自动进入中断入口,无需我们安排入口地址的转移指令
void timer0_interrupt(void) interrupt 1
{
static int t = 0;
Timer0 = COUNT;
TR0 = 1;
//翻转输出//
if(t++ == 60)
{
output =! output;
t = 0;
}
}
关于C51,从标准C到C51,除了多了一些相应的扩展关键字,中断服务函数的写法稍有差异以外。
还要注意有些指令对于特定硬件也许不起实际作用,比如移位指令,在51的硬件里,它只对A其作用。
我曾经试过,的确如此,编译能过,但是不起作用,但是,有些人却说能用,我至今没想明白为什么。
对于有C基础的人来说,这个转变是很简单的,但是,为了写出更好的程序,一定要记住:
你的CPU是51,不是电脑;
另外就是,有一些细节一些的高级话题,不过我也不太了解,这方面的书,很推荐一本 何宗彬 的书。
我传过一本电子版在论坛里。
应该说,这一讲的内容,我讲的很浅,一方面是我自己在这方面了解也就如此而已。另外就是,我个人觉得
这些内容已经差不多够初学者用了。
更多的细节可以在以后实际编程中学习和领会。
写到这里,基本上, for newbie的初级篇就写完了。
本来打算接着写 高级篇,当然了,那是一些我自己也不很清楚的内容,只是抛砖引玉,写出来和大家一起讨论,共同进步。
不过最近比较忙,工作的内容,第一个项目在赶,所以,这一部分内容先放下,另外我也要开始去看labview和虚拟仪器的内容了.......
谢谢大家!