想学习单片机的同学可以关注、私信我或者在评论区回复我要入门。传统上,51单片机一般用keil c集成环境来进行编译开发,然后直接烧录到芯片上去运行,这有几个缺点:

·keil C是商业软件,很多人都想白嫖,而是要么使用盗版(破解版),要么使用它的演化版,前者存在法律风险,也有道德瑕疵,后者有功能上的限制;

·就算keil C买了正版,也有不尽如人意的地方,比如keil C对C99和C11的支持不好;

·直接烧录到芯片比较繁琐,对反复的测试不直观和方便。

对上面的问题,我们可以采用开源和免费的工具来实现编译和仿真来避免这一类的问题。

打开网易新闻 查看精彩图片

首先,我们可以采用开源免费的sdcc来进行编译,关于sdcc的介绍,可以看下面:

SDCC - Small Device C Compilersdcc.sourceforge.net/

SDCCis a retargettable, optimizing Standard C (ANSI C89,ISO C99, ISO C11) compiler suite that targets the Intel MCS51 based microprocessors (8031, 8032, 8051, 8052, etc.), Maxim (formerly Dallas) DS80C390 variants, Freescale (formerly Motorola) HC08 based (hc08, s08), Zilog Z80 based MCUs (z80, z180, gbz80, Rabbit 2000/3000, Rabbit 3000A, TLCS-90), Padauk (pdk14, pdk15) and STMicroelectronics STM8. Work is in progress on supporting the Padauk pdk13 target; Microchip PIC16 and PIC18 targets are unmaintained. SDCC can be retargeted for other microprocessors.
SDCC was originally written by Sandeep Dutta and released under aGPL license.

可见SDCC解决了我们两个大问题:开源免费,以及支持C99和C11(最新版还支持C2x)。

下载安装完成后,可以采用下面的命令来对编好的C程序文件进行编译:

sdcc源文件.c编译选项[-o输出文件名]

简单的使用,我们可以用下面的命令来编译满足C99标准(有少量的不满足)的8051程序:

sdcc源文件.c --std-c99 -o输出文件

除此之外,还可以设置:--std-sdcc99来支持sdcc的扩展功能,或者--std-c11和--std-sdcc11以支持C11的标准(以及sdcc的扩展),和--std-c2x和--std-sdcc2x以支持C2x的草案。

简单归纳一下:

ISO C90 / ANSI C89标准:

·不支持double、long double类型;

·不支持将结构体(struct)和联合体(union)作为函数的参数和返回值;

·不支持 K&R风格的函数定义;

·对于51系列单片机,默认情况下函数是不可重入的(function are not reentrant),意味着默认情况下函数内的变量是static,并被放置在统一的数据空间(data-space),这主要是因为51系列的内存太小的缘故,如果需要变量存放在函数的栈(stack)内,需要单独进行函数的修饰说明,如下:

unsignedcharfoo(chari)__reentrant{...}

或者在编译的时候加上--stack-auto选项,或者如下加上预编译指令:

#pragma stackauto

ISO C99标准:

·(上面C89的那些不支持的内容);

·不支持复合字面量(Compound literals),即能够就地构造一个指定类型的无名对象,在只需要一次数组、结构体或联合体变量时使用,如下简单示例如何使用复合字面量:

int*p=(int[]){2,4};//创建一个无名的 int[2]类型静态存储数组//初始数组为值 {2, 4}//创建指向数组首元素的指针 pconstfloat*pc=(constfloat[]){1e0,1e1,1e2};//只读复合字面量intmain(void){

intn=2,*p=&n;

p=(int[2]){*p};//创建一个无名的 int[2]类型自动存储数组//初始化首个元素为之前 *p所持有的值//初始化第二个元素为零//将首元素的地址存储到 p

structpoint{doublex,y;};

voiddrawline1(structpointfrom,structpointto);

voiddrawline2(structpoint*from,structpoint*to);

drawline1((structpoint){.x=1,.y=1},//创建二个块作用域的结构体(structpoint){.x=3,.y=4});//然后调用 drawline1,以值传递drawline2(&(structpoint){.x=1,.y=1},//创建二个块作用域的结构体&(structpoint){.x=3,.y=4});//然后调用 drawline2,传递其地址}

这真的很可惜,这是C99的很大一个优势,不过8051的sdcc本来就不支持结构体作为函数的参数,所以影响还不大;

·不支持非常量长度数组(Variable-length arrays,VLA),即数组定义时其长度可以是一个变量,下面是简单示例VLA的用法:

intn=1;label:;

inta[n];//重分配 10次,每次拥有不同大小printf("The array has %zu elements\n",sizeofa/sizeof*a);

if(n++<10)gotolabel;//离开作用域的 VLA结束其生存期}

·不支持非ASCII字符的宏名(Non-ASCII characters in macro names)

烧录到stc 8051芯片上的程序,可以用stcflash,这是python脚本,需要安装python环境。

对于8051的仿真,可以采用多种仿真器,其中,最直观简单的是edSim51,这是用java编写的,可以适用在不同的操作系统上,其自带了LED、按键、数码管、ADC、DAC、步进电机等模拟,非常适合教学和学习练习。

打开网易新闻 查看精彩图片
打开网易新闻 查看精彩图片