论文部分内容阅读
【摘 要】 在我们的单片机作品和单片机工程中,单片机C程序的设计和编写工作是一项主要的任务,清晰的编写思路,对C程序结构的熟习和了解,是我们顺利完成软件编写的主要因素。在此,通过对单片机C程序结构的学习研究,和典型综合类源程序的分析和总结。得出单片机C程序编写中各程序功能模块的实现方法,函数运行部位的合理安排布置,全局变量的初始赋值方法和传递方向等思路。
【关键词】 单片机;C程序;编写思路;方法
【中图分类号】G64.23 【文献标识码】A 【文章编号】2095-3089(2015)25-00-02
现在,很多人都在运用单片机,单片机的运用越来越广范,产品也起来越多,更多的人在不断加入单片机开发的队伍。而有部分人就会遇到这样的问题,虽然花了很多时间进行了单片机C语言的学习,也掌握了各种变量的定义、运算符的使用、各种语句的运用、函数的编写方法和单片机各功能模块的运用。但在实际编写一些综合程序时,还是不知该如何下手编写。其原因还是对C程序的总体结构和组成要有一个清晰的了解和认识,特别是要通过对很多典型的、综合的源程序进行分析和总结,领会和找出综合典型程序的结构方法和巧妙的编程思路,才能合理熟练的安排各功能函数,使整个程序按我们的思路合理的组织连接起来。
单片机的硬件结构由单片机的内部功能模块和外部功能单元构成。在软件编写之前,首先确定我们的硬件方案,了解和熟习单片机的内部功能和外部方案,尽量利用单片机的内部资源来设计我们的电子作品。如:内部的I/O口、定时计数器、中断、串口通讯、A/D转换、CCP、看门狗等;外部的ADC0804、ADC0809、DAC0832、LED数码管、1602LCD液晶显示、12864LCD液晶显示、独立键盘、矩阵键盘、电机驱动IC、蜂鸣器等;各种单片机的内部结构、功能各不相同。单片机的硬件设计完成后,就可根据硬件方案和任务来进行软件编写了。
1 单片机C程序的结构特点、作用
1.1单片机软件的结构特点:
单片机C程序与PC机C有很多共同的地方,也有一些区别。函数是C程序的基本组成单位,故C又被称为函数式语言。C程序可由一个或多个函数构成。每个函数实现一定的功能,即功能函数。一个单片机程序软件的总体结构包括:程序开始部分的预处理(头文件、宏定义、全局变量定义、函数说明等);主函数;子函数;中断函。
主函数:一个C程序必须有且只能有一个main()函数,也可以有一个main()函数和若干个其它函数。主函数的位置可在其它函数之前,也可以在之后,但程序运行时,总是首先自动从主函开始执行。
子函数:子函数可有多个,每一个子函数完成一个特定的任务和功能,也就是功能函数。子函数不会自动执行,只能被其它函数调用。
中断函数:中断函数是在中断发生后被执行的函数,定时器中断一般可用来做时间发生,脉冲产生,波形产生等,外中断则可处理一些外部事件。
1.2单片机软件的作用:
单片机软件是对硬件起到设置、控制、驱动的作用,对数据则进行算术运算、逻辑运算。
(1)设置作用:单片机的状态受特殊功能寄存器的控制,一般普通51单片机都有20多个特殊功能寄存器,所有这些寄存器以及端口的初始化等都要靠软件来设置。
(2)控制作用:单片机有一些是开关量控制,如灯的亮灭,电动机的运转和停止,电磁阀的开和关等,这些也是靠软件的位操作和字节操作来进行控制。
(3)驱动作用:有些硬件单元,如:液晶的显示、步进电机的转动等,是需要软件来进行设置、控制以及进行数据调用的,这时的软件对硬件起到了驱动硬件的作用。
2 单片机功能程序、函数的实现方法
单片机需要根据硬件来决定编写哪些功能函数、驱动程序、控制程序。功能函数软件的功能一般都有多种实现方法,选择采用哪种函数软件方法来实现所需要的功能,需要根据具体情况分析、选择、确定。单片机要实现一个功能,可以采用的方法有多种,通过分析确定一种较优的方法。如:
例1:要让单片机输出一定的脉冲,可采用以下方案:
用PWM内部模块
用中断函数
软件语句产生,然后由主函数中的while(1)无限循环调用。
例2:要进行LED数码管显示,可采用以下方案:
用中断函数不断反复执行显示
用主函数中的while(1)无限循环调用显示子函数
例1中,要实现PWM输出是用软件语句产生还是用中断功能产生,还是用PWM功能模块。就要根据硬件配置,如51系列单片机就无PWM内部模块,就只能采用中断方法或软件语句产生,然后由主函数无限调用。如是PIC系列单片机有此功能硬件,则可采用内部PWM模块来实现输出。如中断被占用,也可以采用软件语句来实现。除此之外,还根据其它因素来考虑采用哪一种实施方案。如要求时间精度高一些则宜运用定时计数器中断,如要求不高则可采用软件语句产生的方法。实现单片机功能的方案确定后,就可以开始编写相应的功能程序、函数了。
3 单片机软件编写时,应注重以下几个问题
3.1编写单片机C程序要有清晰的结构思路
1个C程序可由1个或多个源文件组成,而1个源文件又由1个或多个函数组成,一般来说,一个函数就是一个功能模块,就是一个小的任务,多个函数组合起来就可完成一个综合的工程项目。1个源程序,除了预处理部分外,还有其它函数,如:主函数、子函数、中断函数。
编写的子函数、程序,要放到哪类函数来执行,执行部位在哪里,也需要我们有一个总体的构思和安排布置。要区分某段程序是暂时调用执行一下,还是要不断反复运行。如果只是临时调用执行则可设计安排到一般子函数中,如果要不断反复执行的程序段,则要设计安排到定时计数器中断函数中和主函数的while(1)循环中。 如果把所有的程序代码都放在一个main()函数中,程序也可以运行。但是一些结构复杂,功能函数较多,代码量大的程序都放在一个主函数中来执行就显得杂乱了,程序结构会变得混乱不清晰,虽然可以运行,但是可移植性、可读性就差了。就算是自己编写的程序,也不容易理清、读懂。所以要把它们分解编写成多个功能程序、子函数,安排布置到源程序的各类函数中去完整的组织起来运行。
3.2功能程序执行的部位——主函数、子函数、中断函数
一般我们把功能函数划分为,无限循环执行类和临时调用执行类。一般需要不断无限循环执行类的功能程序、函数,如:步进电机驱动程序;舵机转角控制脉冲驱动程序;秒基准时间产生程序;外部传感开关查询程序;软件PWM输出程序;动态LED数码管扫描程序;扫描按键程序等。只是临时调用执行类的功能程序、函数,如:延时函数;初始化函数;开关量执行函数等。
通过对很多典型、综合运用类单片机C程序的研究分析,以极C程序结构的分析,一般把不间断无限循环类安排在中断函数中和主函数的while(1)无限循环中,把临时调用类安排在子函数中。功能函数的分布安排原则一般如下:
(1)一般单片机工作,是采用时间片轮转的方法运行,所以,可将实时性要求不高的工作放在主函数中,依次轮流执行。而实时性要求高的,则要使用中断技术及时处理。
(2)首先把反复定时,时间长和时间基准要求较高的工作如:秒基准时间产生程序、步进电机驱动程序等,安排到中断函数中。其它的一般无限循环执行类,如:动态LED数码管扫描程序;按键扫描程序等,安排到main()函数的while(1)中。
(3)如没有时间基准要求较高的程序、函数,则可以把一般的动态LED数码管扫描程序;按键扫描程序等直接安排到中断函数中。
(4)较长的延时函数中也可插入其它程序,如显示程序、按键判断等。
(5)其它临时调用执行类的程序、函数,如:延时函数;初始化函数;开关量执行函数等,则安排到子函数中供其它函数调用。
例如:“可设置时间的6位LED显示软时钟”程序结构如下:
main( )
{ while( 1)
{
显示函数( ) //将6位时钟的值实时显示
按键扫描函数( ) //选择6位时钟的某位变量,从而增减该变量
} }
1ms延时函数( )
定时器初始化函数( )
定时器中断函数1( ) //50ms中断一次,20次产生一秒,然后对6位数加一赋值。
定时器中断函数2( ) //对按键选择的某位不断赋二个值,新的增减值和熄灭值。
以上这个项目中共用到了6个功能函数,需要不断反复执行的有4个:显示函数()、按键扫描函数()、中断函数1()、中断函数2()。这4个中,中断函数1()和中断函数2()反复定时时间长和时间基准要求较高,所以安排到中断函数中比较合理。显示函数()和按键扫描函数()时间基准要求不太严格则可安排到main()的while(1)无限循环中执行。其它二个子函数则供临时调用。这样,我们把各个功能程序、函数安排分布到各个中断函数、主函数、子函数中,最终形成按我们的要求和运行思路连接起来运行的完整程序。
3.3单片机程序中,要尽可能采用简洁、高效的运算方法
算法就是用C语言编程,数据处理运算的思路方法。单片机的程序算法要尽量运算简单,节约时间。一个算法的运行效率一般用空间复杂度与时间复杂度来衡量。算法的时间复杂度是指算法需要消耗的时间资源。算法的空间复杂度是指算法需要占用的空间资源。不同的算法占用的时间、空间都不相同。编程时应尽可能做到占用空间小,运行时间短,速度快。
例如:P1口接8个小灯,运行左移流水灯。
算法1
void lamp( )
{
uchar i;
P1=0xfe;
for(i=0;i<8;i++)
{
P1=_crol_(P1,1);
Delay(200);
}
}
算法2
void lamp ( )
{
uchar i;
uchar data=0xff;
for(i=0;i<8;i++)
{
P1=data;
delay(200);
data<<=1;
}
}
算法3
void lamp ( )
{
P1=0xfe; delay(200);
P1=0xfd; delay(200);
P1=0xfb; delay(200);
P1=0xf7; delay(200);
.
.
}
从上面三段代码的运行来看,算法1和算法2要优于算法3。
4 对全局变量的起始赋值、传递过程思路要清楚
全局变量的起始赋值和传递方向、执行位置是我们程序设计的一个重要思路,全局变量从哪里赋值开始?传递到哪里?在哪里使用?传递的过程路线都必须思路清晰。如:前例中,主要的全局变量是按键选择位的变量和被选择位的加减值变量,这两个变量都是两个主要的全局变量。两个全局变量的起始赋值都在键盘扫描函数中,由一个按键来决定修改哪位,另二位按键决定该值的加减。第一个全局变量(某位)传递到本函数的加减语句中和中断函数2中;第二个全局变量(加减后的值)则传递到中断函数1中去更新相应位的数值。
5 总结
在单片机C程序的设计和编写工作中,设计和编写的原则和思路是我们完成软件工程的精髓。我们在编写程序时重点要重视二点:
(1)在安排布置反复执行的功能程序、函数时,首先把定时时间长和时间基准要求较高的程序、函数安排到中断函数中;其它的一般无限循环执行类函数则安排到主函数的while(1)中。
(2)全局变量的起始赋值和传递方向、位置,从哪里赋值开始?传递到哪里?在哪里使用?和传递的过程路线要思路清晰。
(3)单片机程序中,要尽可能采用简洁、高效的运算方法。
参考文献
[1]卢伯英译.活学活用PIC单片机C语言编程[M].科学出版社.2012.5
[2]李光飞等.单片机C程序设计实例指导[M].北京航空航天大学出版社.2005.9
[3]刘建清.轻松玩转51单片机语言[M].北京航空航天大学出版社.2011.3
【关键词】 单片机;C程序;编写思路;方法
【中图分类号】G64.23 【文献标识码】A 【文章编号】2095-3089(2015)25-00-02
现在,很多人都在运用单片机,单片机的运用越来越广范,产品也起来越多,更多的人在不断加入单片机开发的队伍。而有部分人就会遇到这样的问题,虽然花了很多时间进行了单片机C语言的学习,也掌握了各种变量的定义、运算符的使用、各种语句的运用、函数的编写方法和单片机各功能模块的运用。但在实际编写一些综合程序时,还是不知该如何下手编写。其原因还是对C程序的总体结构和组成要有一个清晰的了解和认识,特别是要通过对很多典型的、综合的源程序进行分析和总结,领会和找出综合典型程序的结构方法和巧妙的编程思路,才能合理熟练的安排各功能函数,使整个程序按我们的思路合理的组织连接起来。
单片机的硬件结构由单片机的内部功能模块和外部功能单元构成。在软件编写之前,首先确定我们的硬件方案,了解和熟习单片机的内部功能和外部方案,尽量利用单片机的内部资源来设计我们的电子作品。如:内部的I/O口、定时计数器、中断、串口通讯、A/D转换、CCP、看门狗等;外部的ADC0804、ADC0809、DAC0832、LED数码管、1602LCD液晶显示、12864LCD液晶显示、独立键盘、矩阵键盘、电机驱动IC、蜂鸣器等;各种单片机的内部结构、功能各不相同。单片机的硬件设计完成后,就可根据硬件方案和任务来进行软件编写了。
1 单片机C程序的结构特点、作用
1.1单片机软件的结构特点:
单片机C程序与PC机C有很多共同的地方,也有一些区别。函数是C程序的基本组成单位,故C又被称为函数式语言。C程序可由一个或多个函数构成。每个函数实现一定的功能,即功能函数。一个单片机程序软件的总体结构包括:程序开始部分的预处理(头文件、宏定义、全局变量定义、函数说明等);主函数;子函数;中断函。
主函数:一个C程序必须有且只能有一个main()函数,也可以有一个main()函数和若干个其它函数。主函数的位置可在其它函数之前,也可以在之后,但程序运行时,总是首先自动从主函开始执行。
子函数:子函数可有多个,每一个子函数完成一个特定的任务和功能,也就是功能函数。子函数不会自动执行,只能被其它函数调用。
中断函数:中断函数是在中断发生后被执行的函数,定时器中断一般可用来做时间发生,脉冲产生,波形产生等,外中断则可处理一些外部事件。
1.2单片机软件的作用:
单片机软件是对硬件起到设置、控制、驱动的作用,对数据则进行算术运算、逻辑运算。
(1)设置作用:单片机的状态受特殊功能寄存器的控制,一般普通51单片机都有20多个特殊功能寄存器,所有这些寄存器以及端口的初始化等都要靠软件来设置。
(2)控制作用:单片机有一些是开关量控制,如灯的亮灭,电动机的运转和停止,电磁阀的开和关等,这些也是靠软件的位操作和字节操作来进行控制。
(3)驱动作用:有些硬件单元,如:液晶的显示、步进电机的转动等,是需要软件来进行设置、控制以及进行数据调用的,这时的软件对硬件起到了驱动硬件的作用。
2 单片机功能程序、函数的实现方法
单片机需要根据硬件来决定编写哪些功能函数、驱动程序、控制程序。功能函数软件的功能一般都有多种实现方法,选择采用哪种函数软件方法来实现所需要的功能,需要根据具体情况分析、选择、确定。单片机要实现一个功能,可以采用的方法有多种,通过分析确定一种较优的方法。如:
例1:要让单片机输出一定的脉冲,可采用以下方案:
用PWM内部模块
用中断函数
软件语句产生,然后由主函数中的while(1)无限循环调用。
例2:要进行LED数码管显示,可采用以下方案:
用中断函数不断反复执行显示
用主函数中的while(1)无限循环调用显示子函数
例1中,要实现PWM输出是用软件语句产生还是用中断功能产生,还是用PWM功能模块。就要根据硬件配置,如51系列单片机就无PWM内部模块,就只能采用中断方法或软件语句产生,然后由主函数无限调用。如是PIC系列单片机有此功能硬件,则可采用内部PWM模块来实现输出。如中断被占用,也可以采用软件语句来实现。除此之外,还根据其它因素来考虑采用哪一种实施方案。如要求时间精度高一些则宜运用定时计数器中断,如要求不高则可采用软件语句产生的方法。实现单片机功能的方案确定后,就可以开始编写相应的功能程序、函数了。
3 单片机软件编写时,应注重以下几个问题
3.1编写单片机C程序要有清晰的结构思路
1个C程序可由1个或多个源文件组成,而1个源文件又由1个或多个函数组成,一般来说,一个函数就是一个功能模块,就是一个小的任务,多个函数组合起来就可完成一个综合的工程项目。1个源程序,除了预处理部分外,还有其它函数,如:主函数、子函数、中断函数。
编写的子函数、程序,要放到哪类函数来执行,执行部位在哪里,也需要我们有一个总体的构思和安排布置。要区分某段程序是暂时调用执行一下,还是要不断反复运行。如果只是临时调用执行则可设计安排到一般子函数中,如果要不断反复执行的程序段,则要设计安排到定时计数器中断函数中和主函数的while(1)循环中。 如果把所有的程序代码都放在一个main()函数中,程序也可以运行。但是一些结构复杂,功能函数较多,代码量大的程序都放在一个主函数中来执行就显得杂乱了,程序结构会变得混乱不清晰,虽然可以运行,但是可移植性、可读性就差了。就算是自己编写的程序,也不容易理清、读懂。所以要把它们分解编写成多个功能程序、子函数,安排布置到源程序的各类函数中去完整的组织起来运行。
3.2功能程序执行的部位——主函数、子函数、中断函数
一般我们把功能函数划分为,无限循环执行类和临时调用执行类。一般需要不断无限循环执行类的功能程序、函数,如:步进电机驱动程序;舵机转角控制脉冲驱动程序;秒基准时间产生程序;外部传感开关查询程序;软件PWM输出程序;动态LED数码管扫描程序;扫描按键程序等。只是临时调用执行类的功能程序、函数,如:延时函数;初始化函数;开关量执行函数等。
通过对很多典型、综合运用类单片机C程序的研究分析,以极C程序结构的分析,一般把不间断无限循环类安排在中断函数中和主函数的while(1)无限循环中,把临时调用类安排在子函数中。功能函数的分布安排原则一般如下:
(1)一般单片机工作,是采用时间片轮转的方法运行,所以,可将实时性要求不高的工作放在主函数中,依次轮流执行。而实时性要求高的,则要使用中断技术及时处理。
(2)首先把反复定时,时间长和时间基准要求较高的工作如:秒基准时间产生程序、步进电机驱动程序等,安排到中断函数中。其它的一般无限循环执行类,如:动态LED数码管扫描程序;按键扫描程序等,安排到main()函数的while(1)中。
(3)如没有时间基准要求较高的程序、函数,则可以把一般的动态LED数码管扫描程序;按键扫描程序等直接安排到中断函数中。
(4)较长的延时函数中也可插入其它程序,如显示程序、按键判断等。
(5)其它临时调用执行类的程序、函数,如:延时函数;初始化函数;开关量执行函数等,则安排到子函数中供其它函数调用。
例如:“可设置时间的6位LED显示软时钟”程序结构如下:
main( )
{ while( 1)
{
显示函数( ) //将6位时钟的值实时显示
按键扫描函数( ) //选择6位时钟的某位变量,从而增减该变量
} }
1ms延时函数( )
定时器初始化函数( )
定时器中断函数1( ) //50ms中断一次,20次产生一秒,然后对6位数加一赋值。
定时器中断函数2( ) //对按键选择的某位不断赋二个值,新的增减值和熄灭值。
以上这个项目中共用到了6个功能函数,需要不断反复执行的有4个:显示函数()、按键扫描函数()、中断函数1()、中断函数2()。这4个中,中断函数1()和中断函数2()反复定时时间长和时间基准要求较高,所以安排到中断函数中比较合理。显示函数()和按键扫描函数()时间基准要求不太严格则可安排到main()的while(1)无限循环中执行。其它二个子函数则供临时调用。这样,我们把各个功能程序、函数安排分布到各个中断函数、主函数、子函数中,最终形成按我们的要求和运行思路连接起来运行的完整程序。
3.3单片机程序中,要尽可能采用简洁、高效的运算方法
算法就是用C语言编程,数据处理运算的思路方法。单片机的程序算法要尽量运算简单,节约时间。一个算法的运行效率一般用空间复杂度与时间复杂度来衡量。算法的时间复杂度是指算法需要消耗的时间资源。算法的空间复杂度是指算法需要占用的空间资源。不同的算法占用的时间、空间都不相同。编程时应尽可能做到占用空间小,运行时间短,速度快。
例如:P1口接8个小灯,运行左移流水灯。
算法1
void lamp( )
{
uchar i;
P1=0xfe;
for(i=0;i<8;i++)
{
P1=_crol_(P1,1);
Delay(200);
}
}
算法2
void lamp ( )
{
uchar i;
uchar data=0xff;
for(i=0;i<8;i++)
{
P1=data;
delay(200);
data<<=1;
}
}
算法3
void lamp ( )
{
P1=0xfe; delay(200);
P1=0xfd; delay(200);
P1=0xfb; delay(200);
P1=0xf7; delay(200);
.
.
}
从上面三段代码的运行来看,算法1和算法2要优于算法3。
4 对全局变量的起始赋值、传递过程思路要清楚
全局变量的起始赋值和传递方向、执行位置是我们程序设计的一个重要思路,全局变量从哪里赋值开始?传递到哪里?在哪里使用?传递的过程路线都必须思路清晰。如:前例中,主要的全局变量是按键选择位的变量和被选择位的加减值变量,这两个变量都是两个主要的全局变量。两个全局变量的起始赋值都在键盘扫描函数中,由一个按键来决定修改哪位,另二位按键决定该值的加减。第一个全局变量(某位)传递到本函数的加减语句中和中断函数2中;第二个全局变量(加减后的值)则传递到中断函数1中去更新相应位的数值。
5 总结
在单片机C程序的设计和编写工作中,设计和编写的原则和思路是我们完成软件工程的精髓。我们在编写程序时重点要重视二点:
(1)在安排布置反复执行的功能程序、函数时,首先把定时时间长和时间基准要求较高的程序、函数安排到中断函数中;其它的一般无限循环执行类函数则安排到主函数的while(1)中。
(2)全局变量的起始赋值和传递方向、位置,从哪里赋值开始?传递到哪里?在哪里使用?和传递的过程路线要思路清晰。
(3)单片机程序中,要尽可能采用简洁、高效的运算方法。
参考文献
[1]卢伯英译.活学活用PIC单片机C语言编程[M].科学出版社.2012.5
[2]李光飞等.单片机C程序设计实例指导[M].北京航空航天大学出版社.2005.9
[3]刘建清.轻松玩转51单片机语言[M].北京航空航天大学出版社.2011.3