首页技术单片机c语言代码大全 单片机c语言

单片机c语言代码大全 单片机c语言

编程之家2026-06-27661次浏览

这篇文章给大家聊聊关于单片机c语言代码大全,以及单片机c语言对应的知识点,希望对各位有所帮助,不要忘了收藏本站哦。

单片机c语言代码大全 单片机c语言

如何写出高效的单片机C语言程序代码

由于单片机的性能同电脑的性能是天渊之别的,无论从空间资源上、内存资源、工作频率,都是无法

与之比较的。PC机编程基本上不用考虑空间的占用、内存的占用的问题,最终目的就是实现功能就可以了。

对于单片机来说就截然不同了,一般的单片机的Flash和Ram的资源是以KB来衡量的,可想而知,单片

机的资源是少得可怜,为此我们必须想法设法榨尽其所有资源,将它的性能发挥到最佳,程序设计时必须

遵循以下几点进行优化:

1.使用尽量小的数据类型

单片机c语言代码大全 单片机c语言

能够使用字符型(char)定义的变量,就不要使用整型(int)变量来定义;能够使用整型变量定义的变

量就不要用长整型(long int),能不使用浮点型(float)变量就不要使用浮点型变量。当然,在定义变

量后不要超过变量的作用范围,如果超过变量的范围赋值,C编译器并不报错,但程序运行结果却错了,

而且这样的错误很难发现。

2.使用自加、自减指令

通常使用自加、自减指令和复合赋值表达式(如a-=1及a+=1等)都能够生成高质量的

单片机c语言代码大全 单片机c语言

程序代码,编译器通常都能够生成inc和dec之类的指令,而使用a=a+1或a=a-1之类

的指令,有很多C编译器都会生成二到三个字节的指令。

3.减少运算的强度

可以使用运算量小但功能相同的表达式替换原来复杂的的表达式。

(1)求余运算

N= N%8可以改为N= N&7

说明:位操作只需一个指令周期即可完成,而大部分的C编译器的“%”运算均是调用子程序来

完成,代码长、执行速度慢。通常,只要求是求2n方的余数,均可使用位操作的方法来代替。

(2)平方运算

N=Pow(3,2)可以改为N=3*3

说明:在有内置硬件乘法器的单片机中(如51系列),乘法运算比求平方运算快得多,因为浮点数

的求平方是通过调用子程序来实现的,乘法运算的子程序比平方运算的子程序代码短,执行速度快。

(3)用位移代替乘法除法

N=M*8可以改为N=M<<3

N=M/8可以改为N=M>>3

说明:通常如果需要乘以或除以2n,都可以用移位的方法代替。如果乘以2n,都可以生成左移

的代码,而乘以其它的整数或除以任何数,均调用乘除法子程序。用移位的方法得到代码比调用乘除法子

程序生成的代码效率高。实际上,只要是乘以或除以一个整数,均可以用移位的方法得到结果。如N=M*9

可以改为N=(M<<3)+M;

(4)自加自减的区别

例如我们平时使用的延时函数都是通过采用自加的方式来实现。

void DelayNms(UINT16 t)

{

UINT16 i,j;

for(i=0;i<t;i++)

for(j=0;i<1000;j++)

}

可以改为

void DelayNms(UINT16 t)

{

UINT16 i,j;

for(i=t;i>=0;i--)

for(j=1000;i>=0;j--)

}

说明:两个函数的延时效果相似,但几乎所有的C编译对后一种函数生成的代码均比前一种代码少1~3

个字节,因为几乎所有的MCU均有为0转移的指令,采用后一种方式能够生成这类指令。

4. while与do...while的区别

void DelayNus(UINT16 t)

{

while(t--)

{

NOP();

}

}

可以改为

void DelayNus(UINT16 t)

{

do

{

NOP();

}while(--t)

}

说明:使用do…while循环编译后生成的代码的长度短于while循环。

5. register关键字

void UARTPrintfString(INT8*str)

{

while(*str&& str)

{

UARTSendByte(*str++)

}

}

可以改为

void UARTPrintfString(INT8*str)

{

register INT8*pstr=str;

while(*pstr&& pstr)

{

UARTSendByte(*pstr++)

}

}

说明:在声明局部变量的时候可以使用register关键字。这就使得编译器把变量放入一个多用途的寄存

器中,而不是在堆栈中,合理使用这种方法可以提高执行速度。函数调用越是频繁,越是可能提高代码的

速度,注意register关键字只是建议编译器而已。

6. volatile关键字

volatile总是与优化有关,编译器有一种技术叫做数据流分析,分析程序中的变量在哪里赋值、在

哪里使用、在哪里失效,分析结果可以用于常量合并,常量传播等优化,进一步可以死代码消除。一般来

说,volatile关键字只用在以下三种情况:

a)中断服务函数中修改的供其它程序检测的变量需要加volatile(参考本书高级实验程序)

b)多任务环境下各任务间共享的标志应该加volatile

c)存储器映射的硬件寄存器通常也要加volatile说明,因为每次对它的读写都可能由不同意义

总之,volatile关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素

更改,比如:操作系统、硬件或者其它线程等。遇到这个关键字声明的变量,编译器对访问该变量的代码

就不再进行优化,从而可以提供对特殊地址的稳定访问。

51单片机C语言程序

//你原来的b2,b2都是死循环,这是不行的,只有主函数才可以死循环。

//你的主函数结构也有问题。

//为你增加了一个按键检测的函数。

//下列程序通过了实验测试。

//b1输出的周期大约0.9s。

//b2输出的周期大约0.6s。

//K为触动开关,reg为红灯,bice为绿灯,b1、b2各为一个方波,

//按第一次触动开关时红灯亮、b1输出,

//按第二次绿灯亮、为b2输出,

//按第三次都关闭.

#include<reg51.h>

#define uint unsigned int

#define uchar unsigned char

uint a;

void b1();

void b2();

sbit t= P1^0;

sbit k= P3^5;

sbit reg= P3^3;

sbit bice= P3^2;

void delay(uchar z)

{

uint x,y;

for(x= z; x> 0; x--) for(y= 110; y> 0; y--);

}

bit key()

{

bit kkk;

kkk= k;//读入按键.

if(kkk== 1) return 0;//没有按下.

delay(5);//延时.

if(k== kkk) return 1;//两次相等.

return 0;

}

void main()

{

while(1){

P3= 0xff;

while(!key());//静等按下第一次.

reg= 0;

bice= 1;

while(!key()) b1();//没有按下第二次就循环等待.

reg= 1;

bice= 0;

while(!key()) b2();//没有按下第三次就循环等待.

}

}

void b1()

{

P1= 0xfe; a= 50000; while(a--);

P1= 0xff; a= 50000; while(a--);

}

void b2()

{

P1= 0xfe; a= 30000; while(a--);

P1= 0xff; a= 30000; while(a--);

}

单片机C语言编写共阳0~999,最好解释详细点!

/***数显秒表,范围0~999***/

/***源程序默认硬件环境:52单片机,12MHz晶振,3位共阳数码管,P0口段选,P10~P12高电平位选(NPN三极管驱动),P12为最高位数码管***/

#include"reg52.h"//包含52头文件

#define TRUE 1//定义布尔量'1':真

#define FALSE 0//定义布尔量'0':假

#define uchar unsigned char//定义无符号字符型数据简称

#define uint unsigned int//定义无符号整型数据简称

#define th0 0xfc

#define tl0 0x18//1ms at 12MHz(定时器工作模式1状态)

#define SEG_Num 3//数码管位数

#define SEG_Data P0//数码管段驱动接口

#define SEG_En P1//数码管位驱动接口

#define SEG_AllOff(SEG_En&=0xf8)//关闭所有数码管(位驱动)

#define DisTimeAt1msCount 5//单'位'数码管显示时间,数码管刷新频率f=1/(N×t),其中 N为数码管位数, t为单'位'数码管显示时间

#define T1sAt1msCount 1000//1秒计数值(在定时器为1ms情况下计数)

#define TimesEnd 1000//显示内容范围 0~999

uchar code SEG_B_List[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};//共阳数码管代码表"0-9"

uint Sec;

uchar bdata Flag=1;

sbit DisplayFlag=Flag^0;//显示标志位

sbit TimesUpFlag=Flag^1;//时间更新标志位

void Timer0() interrupt 1//定时器0中断函数

{

static uchar t1ms;//定义静态变量 t1ms定时计数寄存空间

static uint t1ms_sec;

TL0=tl0;

TH0=th0;//重赋 1ms定时初值

t1ms=++t1ms%DisTimeAt1msCount;//先计数值加1,后对计数范围进行限制0~(DisTimeAt1msCount-1)

if(!t1ms) DisplayFlag=TRUE;//若定时计数值归0,则表示计数值曾到达单'位'显示时间(DisTimeAt1msCount),显示标志置位

t1ms_sec=++t1ms_sec%T1sAt1msCount;//在 T1sAt1msCount(1000)范围内加1

if(!t1ms_sec) TimesUpFlag=TRUE;//若归0,则1s时间到,时间更新标志位置位

}

void SystemInit()//系统初始化函数

{

TMOD=0x01;//关闭定时器1,开启定时器0,且工作在模式1(16位定时器)

TH0=th0;

TL0=tl0;//装定时初值(1ms at 12MHz)

TR0=1;//启动计时

ET0=1;//允许定时器0中断

EA=1;//开启系统中断功能

}

float Pow_Self(float x,uint y)//自编简易 x的 y次方函数,y只能是非负整数

{

float sum;

if(x==0&& y==0) return;//0的 0次方无意义

else if(x==0) sum=0;//可有可无,y!=0的情况已经包含x=0,不加不影响结果,但影响运算速度

else if(y==0) sum=1;//除上述情况外,任何数的 0次方均为 1

else if(y==1) sum=x;//任何数的 1次方均为本身

else if(y>1) sum=Pow_Self(x,--y)*x;//递归调用,降幂

return sum;//返回计算结果

}

void TimesUpdata()//时间更新函数

{

if(TimesUpFlag)//若时间更新标志为真

{

Sec=++Sec%TimesEnd;//Sec(秒)在 TimesEnd(0~999)范围内加1

TimesUpFlag=FALSE;//清时间更新标志位

}

}

void Display(uint dis_num)//显示函数,显示内容为无符号整型数据 dis_num

{

static uchar dis_loca;//定义静态变量显示位置

if(DisplayFlag)//若显示标志位为真(单'位'显示时间结束),则执行以下任务

{

DisplayFlag=FALSE;//清显示标志位

dis_loca=++dis_loca%SEG_Num;//先对显示位置加1,后对变量范围进行限制 0~(SEG_Num-1)

SEG_AllOff;//关闭所有数码管显示(位驱动)

SEG_Data=SEG_B_List[(dis_num/(uint)(Pow_Self(10,dis_loca)))%10];//将显示内容(dis_num)本次需显示的位(dis_loca)上的数值转成代码,并送到数据端口

SEG_En|=1<<dis_loca;//开启本次需要显示的位驱动

}

}

void main()//主函数

{

SystemInit();//调用系统初始化函数

while(1)//循环系统

{

TimesUpdata();//调用时间更新函数

Display(Sec);//调用显示函数显示内容为 Sec

}

}

文章分享结束,单片机c语言代码大全和单片机c语言的答案你都知道了吗?欢迎再次光临本站哦!

dnf粉红宝盒能开出什么(炼兽宝盒开出几率低吗)dnf武器锻造,dnf怎么快速锻造8