单片机的C语言编程是不同于传统的C语言的编程的,这是与它本身的体系结构有关。单片机编程是软硬件结合比较精密的。如果没有一些硬件方面的知识可能大家很难编出正确的程序。
如有的同学的主程序是类似这样的结构
void main(void)
{
P0 = 0xff ;
sleep(1000) ;
P0 = 0x00 ;
sleep(1000) ;
}
仿真的时候可能会看到灯是闪烁的。但事实上这样的程序是不对的。也有同学发现了这个问题,我看到他都把汇编代码贴出来了。
分析下上面的程序的流程 P0口输出高电平---->延时一会儿----->P0口输出低电平----->延时一会儿。 这样接在P0口上的LED就会亮暗的闪烁。如果要一直这样循环闪烁下去呢?看到这里大家发现问题了没有?
问题就在这里了,我们想让它循环闪烁,但是回过头来看看我们的主程序,有循环的地方吗?
之所以这样的程序仿真的时候还是正确的,那是因为编译器在生成汇编代码的时候已经自动加上了跳转语句,主程序执行完了之后就重新跳转到初始化处重新执行。
所以上面这段程序的流程是这个样子的:
初始化(内部RAM,堆栈初始化,由编译器自动生成相应代码) --------> 跳转到用户的主程序-------->主程序执行完毕---->再次跳转到初始化处,重新执行。
上面这个流程是我们不想要的。因为初始化是只需要在开机的时候(系统上电)时候初始化一次的时候。想想看如果你的手机每次开机完成之后如果没有按键按下去或者收到短信电话什么的,就会重新初始化一次,是什么后果:) 估计你肯定会扔了那手机,骂道这是谁写的程序呀。
我们希望初始化完成之后,程序就会跳入到主程序(main函数)中去,并且始终循环执行里面的代码(哪怕没有任务,只在那里空跳转循环) 因为只有那里面的代码(中断函数同样属于)才是属于我们用户编写的有用代码,是希望按照我们的意图去执行的。所以我们希望的正确流程是如下的:
初始化(内部RAM,堆栈初始化,由编译器自动生成相应代码) --------> 跳转到用户的主程序-------->主程序执行完毕---->
继续执行主循环里面的用户代码。
理解了上面的那个流程,我们正确的函数应该是如下的。
void main(void)
{
while(1) //循环条件,永远为真,下面复合语句里面的内容会一直循环执行
{
P0 = 0xff ;
sleep(1000) ;
P0 = 0x00 ;
sleep(1000) ;
}
}
当然循环语句的写法不止这一种,我在第十三课 C51循环语句里有详细的介绍 :http://www.51hei.com/mcuteach/136.html
小结一下:基于单片机的程序是一个死循环。所有的代码和函数调用都应该在这个循环里面,(中断函数例外,在进入循环之前可以调用其它的一些初始化的函数或者是其它只需要在系统上电调用一次的函数或者代码)。
基本框架如下
void main(void)
{
// 初始化函数,根据实际系统情况编写
while(1) //死循环 也可以用for(;;;)形式或其它形式
{
//任务函数1
//任务函数2
..........
}
}
先写到这里。
关键字:单片机程序 基本框架 任务函数
引用地址:
单片机程序该如何写
推荐阅读最新更新时间:2024-03-16 13:06
ADC0832模数转换MSP430单片机程序+电路图
下面是电路图: ADC0832封装图 ADC0832与单片机连接图 ADC0832时序图 程序源码下载: #include msp430f2121.h #define DO (P1IN&BIT7) #define uchar unsigned char #define uint unsigned int /*********************************************** sbit cs=P2^0; sbit clk=P2^1; sbit DI=P2^2; sbit DO=P2^6; ***************************************
[单片机]
stc51单片机硬件SPI驱动nrf24l01程序
stc51系类单片机大多数带SPI模块,例如STC12C5608AD,就带有SPI口,可以直接用此SPI口驱动nrf24l01,省去模拟SPI的麻烦。 spi初始化代码如下: void SPI_Init(void) { SPSTAT |= 0XC0; // 清高两位, SPCTL = 0XD0; // 设置为主模式,开SPI } spi收发数据代码如下: uchar SPI_RW(uchar tr_data) { uchar i=0; SPSTAT |= 0Xc0; // 清高两位, SPDAT=tr_data; while(((SPSTAT&0X80)!=0X80)&&(i 20)) { i++; delay_ms(1)
[单片机]
AVR单片机C语言程序设计中的位操作
在标准C语言的的教材中,对于位运算的操作是基本不涉及的,但是在单片机系统的程序中,需要经常操作各类以字节为单位的寄存器,而这些寄存器通常都是以二进制中的位为控制单位的数据组合。往往一个8位寄存器中的每一位都有各自的控制对象,例如端口B的方向寄存器DDRB,如下图所示 它实际上控制着PB口的8个端口PB0-PB7的方向,也就是说它的每一位都控制一个端口的方向,如果我们要把端口PB0-PB3设置为输出口,而把PB4-PB7设置为输入口,在不用位运算符的情况下,我们可以直接使用赋值语句DDRB=0x0f来实现,这样是完全可以实现的。 但是如果出现下面的情况:在程序中PB口的8位端口的状态本来是1、3、5、7为输入。0、2
[单片机]
编制单片机应用程序的步骤和难点
1前言 如何编写单片机应用程序,这是一个实践性很强的题目,也是1项艰苦而细致的工作。如果按照一定的步骤并且找出难点,事先对这些难点加以处理,能够收到事半功倍的效果。下面根据实际工作中的经验,谈谈实际开发中必经的几个步骤和可能遇到的难点的处理。对于1个单片机应用程序,其编制过程如图1所示。 2编制步骤 2.1搞清功能和编写方案 接到一个单片机项目设计文件之后,并不是马上动手编写程序,而是仔细研究用户提出的技术要求或者技术说明,根据这些技术要求和技术说明,也就是客户要求,把程序应该具备的主要功能写清楚,写仔细,这是最关键的工作。如不清楚,应向客户和使用者问清楚,否则在设计完成以后会发现有些功能由于事先没有考虑清楚再重新设计将
[单片机]
TX-1C单片机开发板的Proteus仿真版与程序源码
郭天祥仿真单片机开发板的proteus原理图如下 测板程序介绍: 本程序为实验板的总体测试程序,综合测试了整个实验板上的绝大多数功能,用户可不用测试。 下载程序后会依次看到以下5种状态。 1.8个流水灯先会从上到下流动一遍,同时蜂鸣器发声。 2.接着DAC电流指示灯由暗变亮 3.接着前三位数码管显示温度值 4.接着AD数值显示在数码管的前三位 5.接着等待矩阵键盘的按下,按下后相应的数码显示在数码管的后三位上, 下面是其中的单键识别源程序: #include reg52.h sbit BY1=P3^4; //定义按键的输入端S2键 unsigned char count; //按键计数,每按一下,count加1 u
[单片机]
超声波测距单片机C程序
单片机源程序如下: #include reg52.h //STC89C52头文件 #define uchar unsigned char #define uint unsigned int unsigned int time=0; unsigned int timer=0; unsigned long S=0; //距离变量 bit flag =0; //超声波模块量程溢出标志( 5米时置1) sbit echo=P1^0; //超声波模块的发射端 sbit trig=P1^1; //超声波模块的接收端 sbit ds=P2^2; //DS18B2
[单片机]
凌阳61单片机使用7段数码管显示数字时钟的程序
#include SPCE061v004.h #include unspmacro.h //中断函数定义 void IRQ1(void) __attribute__((ISR)); void IRQ5(void) __attribute__((ISR)); void IRQ6(void) __attribute__((ISR)); enum { RUN, CHGSECOND, CHGMINUTE, CHGHOUR } clock_status; //时钟的状态 unsigned int hour,minute,second; unsigned int show_hour, show_minute, show_sec
[单片机]
单片机程序设计中运用事件驱动机制
摘要: 通过实例说明将事件驱动机制应用到单片机程序中,使中断响应与处理程序分离,可较理想地用硬件定时代替处理程序中的软件定时,从而大幅提高系统对多中断的实时响应能力,降低多中断系统调试的难度。
关键词: 事件驱动 单片机 程序设计 实时响应
1 传统单片机程序开发的不足
在传统的单片机程序中,通常是以“过程”和“操作”为中心的结构,程序按规定的过程顺序地执行,与外设的连接一般采用中断方式,在中断服务程序中完成外设的全部处理工作,主程序一般是初始化系统并等待中断的发生。这种结构成熟、易于理解,但有如下不足:
(1)受单片机性能的限制,容易造成系统对其它中断的响应变得迟缓,特别是对于中断源较
[应用]