原创首发于CSDN,转载请注明出处,谢谢!
文章目录
- 为何会在Linux下开发单片机
- 个人系统环境与所用开发板
- 安装开源编译器 sdcc
- STC MCU ISP 闪存工具 stcgal 的安装
- 单片机代码的编译与测试
- |编写主代码 main.c
- |使用 sdcc 编译
- |闪存烧录 stcgal
- 单片机效果展示
- 拓展1⃣️:使用SDCC进行单片机程序编写的不同点
- 拓展2⃣️:附头文件 8051.h 文本
- 参考资料
- 文章更新时间记录
为何会在Linux下开发单片机
个人初步学习51单片机的时,所能接触到的教程基本都是在Windows环境下使用Keil开发。诚然,Keil确实是一款强大的开发软件,但博主个人受限于以下因素:
- 个人使用的是苹果电脑 MacBook Air;
- 所装的VM虚拟机里已经安装了 Ubuntu 20.04.01。
加之其他琐碎的原因,博主终是走上了适配在Linux环境下的开源编译器SDCC来开发单片机这条路【不止是现在的C51单片机,还有以后的STM32,统一在Linux环境下进行开发 】。其实两者在抛开系统环境、编译软件的差异,大体上都是一样的:①【SDCC、Keil】编译生成hex文件;②【stcgal、stc-isp】启动烧录软件烧录程序。
在Ubuntu系统下搭建51单片机开发环境全过程里,出乎预料的反而是察觉了个人对于Linux系统的 文件架构、软硬链接、软链接的“漂移”、环境变量 等几个方面的认识不足,惹出了几个无厘头的“bug”。 故才有了“参考资料”一节内那几篇环境变量、系统变量的博文,对于这几个主题的研究,以后也会出几篇相关内容的博文。
个人系统环境与所用开发板
- 电脑:MacBook Air
- 虚拟机:VMWare Fusion 12
- Linux系统:Ubuntu 20.04.01
- 开发板:普中HC6800V2.0 (开发板实物请跳转到“单片机效果展示”一节。)
安装开源编译器 sdcc
终端输入指令 sudo -i 进入根目录 /,再次输入指令 sudo apt-get install sdcc
。安装完毕,全程无报错。终端输入指令 sdcc -v 验证编译器是否安装成功:
∗ \ast ∗小贴士:SDCC的全称是Small Device C Compiler,即“小型设备C语言编译器”。根据官网(http://sdcc.sourceforge.net/)的说法,SDCC是一个可重定向目标的、优化的标准C编译器套件(支持ANSI C89、ISO C99和ISO C11),支持基于英特尔MCS51(8031、8032、8051、8052等)、Maxim(原Dallas)的DS80C390系列、Freescale(原摩托罗拉)的HC08系列(hc08、s08)、Zilog的Z80系列(z80、z180、gbz80、Rabbit 2000/3000、Rabbit 3000A、TLCS-90)、Padauk(pdk14、pdk15)和意法半导体的STM8。
图片里打框的MCS51就是我们常说的51单片机,在根目录里进入路径 usr/share/sdcc/include/mcs51 输入 ls,会显示出一堆不同型号的51单片机芯片的适配头文件。至此,编译器SDCC的安装大功告成。
STC MCU ISP 闪存工具 stcgal 的安装
在根目录 / 下输入指令 pip3 install stcgal
(系统没有安装 pip3 就自己下载安装),安装的同时会下载两个软件 tqdm-4.64.1 与 pyserial-3.5 。前者显示文件 main.hex 的烧录进度条,后者则是串口通信软件。(记住了,不管安装什么软件,在安装之前必须要好好查一查其具体的功能是什么。)
单片机代码的编译与测试
|编写主代码 main.c
#include <mcs51/8051.h>
void Delay(unsigned int ms);
void main(){
while(1){
//自行对照开发板引脚图。
P1_1 = 0;
Delay(500);
P1_1 = 1;
//led灯以一秒为一个周期闪烁。
Delay(500);
}
}
void Delay(unsigned int ms){
unsigned int a, b;
for(a = ms; a > 0; a--){
for(b = 100; b > 0; b--);
}
}
|使用 sdcc 编译
在终端前后输入以下两条指令,经过sdcc的编译,测试文件夹内会多出一堆的文件,我们需要的主文件是 main.hex
sdcc main.c
//sdcc默认生成的文件后缀不是hex而是ihx,需要使用packihx转换。
packihx main.ihx > main.hex && ls
搜索相关资料的时候发现了第三条指令:makebin (makebin main.ihx > main.bin)。原来与 ∗ \ast ∗.hex 格式文件相比, ∗ \ast ∗.bin 格式有文件三个方面的差异(请自行验证):
- HEX文件是包括地址信息的,而BIN文件格式只包括了数据本身。 在烧写/下载HEX文件时一般不需要用户指定地址,因为HEX文件内部信息已经包括了地址,而烧写BIN文件时,用户必须指定地址信息;
- BIN文件。对二进制文件而言,没有格式,文件只是纯粹的二进制数据。
- HEX文件使用ASCII来表示二进制的数值。 如一般的8-BIT的二进制数值0x3F,用ASCII来表示就需要表示字符‘3’和字符‘F’,每个字符需要一个BYTE,所以 HEX文件需要大于BIN文件2倍的内存空间。
|闪存烧录 stcgal
用USB线连接电脑将与单片机(请自行安装与系统版本对应的CH341驱动,无头绪的读者请参考下列第二篇博文《搭建Ubuntu的51单片机开发环境(学习记录)》里对应的驱动安装一节),输入指令 ls /dev/tty ∗ \ast ∗ 确认USB接入后在终端输入指令
stcgal -P stc89 -p /dev/ttyUSB0 main.hex
或者直接输入
stcgal main.hex
笔者在烧录程序时直接用第二条,在上文里代码头文件已经选择了51单片机类型为 8051 #include <mcs51/8051.h>
,个人认为 stcgal 运行时默认 port 为 /dev/ttyUSB0,故使用时直接运行,无需手动指定端口和波特率。
单片机效果展示
单片机的LED灯模块,右边数第一个LED灯以一秒为一个周期闪烁。
拓展1⃣️:使用SDCC进行单片机程序编写的不同点
SDCC支持的C语言与Keil的差异:
- 包含自定义的头文件时必须使用双引号。 某个项目中有个名为tm1638.h 的文件,在Keil写成 #include <tm1638.h> ,但在SDCC中必须写成 #include “tm1638.h” ;
- sdcc编译51单片机代码文件的头文件(引脚定义文件)名字不一样。 Keil中为 #include <reg52.h>,而在SDCC中需要写成 #include <mcs51/8051.h>;
- Keil中的特殊类型 sbit 和 sfr 在SDCC中为 __sbit和 __sfr 。 如Keil中的代码 sfr P0 = 0x80、sbit P0_1 = P0 ^ 1。在SDCC中就要写成:__sfr __at (0x80) P0、__sbit __at (0x81) P0_1 。但在8051.h 中已经定义了常用的端口,需要使用哪个端口时,直接使用P0、P1、P2_1之类的宏即可;
- Keil中的code关键字(用于将数据放入代码段)在SDCC中应该写成__code。 在Keil中的代码unsigned char code sevenseg_hex[] = { … },在SDCC中应该这样写:__code unsigned char sevenseg_hex[] = { … };
- Keil中的 interrupt 关键字在SDCC中应该写成 __interrupt。 定义中断处理函数的代码在SDCC中应该写成:void timer0() __interrupt 1 { … } 。
< 请读者自行验证以上,同时欢迎在评论区补充不同的差异点。>
拓展2⃣️:附头文件 8051.h 文本
/*-------------------------------------------------------------------------
8051.h: Register Declarations for the Intel 8051 Processor
Copyright (C) 2000, Bela Torok / bela.torok@kssg.ch
This library is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this library; see the file COPYING. If not, write to the
Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301, USA.
As a special exception, if you link this library with other files,
some of which are compiled with SDCC, to produce an executable,
this library does not by itself cause the resulting executable to
be covered by the GNU General Public License. This exception does
not however invalidate any other reasons why the executable file
might be covered by the GNU General Public License.
-------------------------------------------------------------------------*/
#ifndef REG8051_H
#define REG8051_H
/* BYTE Register */
__sfr __at (0x80) P0 ;
__sfr __at (0x81) SP ;
__sfr __at (0x82) DPL ;
__sfr __at (0x83) DPH ;
__sfr __at (0x87) PCON ;
__sfr __at (0x88) TCON ;
__sfr __at (0x89) TMOD ;
__sfr __at (0x8A) TL0 ;
__sfr __at (0x8B) TL1 ;
__sfr __at (0x8C) TH0 ;
__sfr __at (0x8D) TH1 ;
__sfr __at (0x90) P1 ;
__sfr __at (0x98) SCON ;
__sfr __at (0x99) SBUF ;
__sfr __at (0xA0) P2 ;
__sfr __at (0xA8) IE ;
__sfr __at (0xB0) P3 ;
__sfr __at (0xB8) IP ;
__sfr __at (0xD0) PSW ;
__sfr __at (0xE0) ACC ;
__sfr __at (0xF0) B ;
/* BIT Register */
/* P0 */
__sbit __at (0x80) P0_0 ;
__sbit __at (0x81) P0_1 ;
__sbit __at (0x82) P0_2 ;
__sbit __at (0x83) P0_3 ;
__sbit __at (0x84) P0_4 ;
__sbit __at (0x85) P0_5 ;
__sbit __at (0x86) P0_6 ;
__sbit __at (0x87) P0_7 ;
/* TCON */
__sbit __at (0x88) IT0 ;
__sbit __at (0x89) IE0 ;
__sbit __at (0x8A) IT1 ;
__sbit __at (0x8B) IE1 ;
__sbit __at (0x8C) TR0 ;
__sbit __at (0x8D) TF0 ;
__sbit __at (0x8E) TR1 ;
__sbit __at (0x8F) TF1 ;
/* P1 */
__sbit __at (0x90) P1_0 ;
__sbit __at (0x91) P1_1 ;
__sbit __at (0x92) P1_2 ;
__sbit __at (0x93) P1_3 ;
__sbit __at (0x94) P1_4 ;
__sbit __at (0x95) P1_5 ;
__sbit __at (0x96) P1_6 ;
__sbit __at (0x97) P1_7 ;
/* SCON */
__sbit __at (0x98) RI ;
__sbit __at (0x99) TI ;
__sbit __at (0x9A) RB8 ;
__sbit __at (0x9B) TB8 ;
__sbit __at (0x9C) REN ;
__sbit __at (0x9D) SM2 ;
__sbit __at (0x9E) SM1 ;
__sbit __at (0x9F) SM0 ;
/* P2 */
__sbit __at (0xA0) P2_0 ;
__sbit __at (0xA1) P2_1 ;
__sbit __at (0xA2) P2_2 ;
__sbit __at (0xA3) P2_3 ;
__sbit __at (0xA4) P2_4 ;
__sbit __at (0xA5) P2_5 ;
__sbit __at (0xA6) P2_6 ;
__sbit __at (0xA7) P2_7 ;
/* IE */
__sbit __at (0xA8) EX0 ;
__sbit __at (0xA9) ET0 ;
__sbit __at (0xAA) EX1 ;
__sbit __at (0xAB) ET1 ;
__sbit __at (0xAC) ES ;
__sbit __at (0xAF) EA ;
/* P3 */
__sbit __at (0xB0) P3_0 ;
__sbit __at (0xB1) P3_1 ;
__sbit __at (0xB2) P3_2 ;
__sbit __at (0xB3) P3_3 ;
__sbit __at (0xB4) P3_4 ;
__sbit __at (0xB5) P3_5 ;
__sbit __at (0xB6) P3_6 ;
__sbit __at (0xB7) P3_7 ;
__sbit __at (0xB0) RXD ;
__sbit __at (0xB1) TXD ;
__sbit __at (0xB2) INT0 ;
__sbit __at (0xB3) INT1 ;
__sbit __at (0xB4) T0 ;
__sbit __at (0xB5) T1 ;
__sbit __at (0xB6) WR ;
__sbit __at (0xB7) RD ;
/* IP */
__sbit __at (0xB8) PX0 ;
__sbit __at (0xB9) PT0 ;
__sbit __at (0xBA) PX1 ;
__sbit __at (0xBB) PT1 ;
__sbit __at (0xBC) PS ;
/* PSW */
__sbit __at (0xD0) P ;
__sbit __at (0xD1) F1 ;
__sbit __at (0xD2) OV ;
__sbit __at (0xD3) RS0 ;
__sbit __at (0xD4) RS1 ;
__sbit __at (0xD5) F0 ;
__sbit __at (0xD6) AC ;
__sbit __at (0xD7) CY ;
/* BIT definitions for bits that are not directly accessible */
/* PCON bits */
#define IDL 0x01
#define PD 0x02
#define GF0 0x04
#define GF1 0x08
#define SMOD 0x80
/* TMOD bits */
#define T0_M0 0x01
#define T0_M1 0x02
#define T0_CT 0x04
#define T0_GATE 0x08
#define T1_M0 0x10
#define T1_M1 0x20
#define T1_CT 0x40
#define T1_GATE 0x80
#define T0_MASK 0x0F
#define T1_MASK 0xF0
/* Interrupt numbers: address = (number * 8) + 3 */
#define IE0_VECTOR 0 /* 0x03 external interrupt 0 */
#define TF0_VECTOR 1 /* 0x0b timer 0 */
#define IE1_VECTOR 2 /* 0x13 external interrupt 1 */
#define TF1_VECTOR 3 /* 0x1b timer 1 */
#define SI0_VECTOR 4 /* 0x23 serial port 0 */
#endif
参考资料
- 《Mac版下实现51单片机进行开发的环境搭建》,CSDN博主:熺子,时间:2022年3月29日;
- 《搭建Ubuntu的51单片机开发环境(学习记录)》,CSDN博主:横着望的猫,时间:2021年12月20日;
- 《Linux(Ubuntu)下51单片机的开发环境的配置及详细的操作步骤》,CSDN博主:逗比小憨憨,时间:2021年2月4日;
- 《如何在Linux下进行51单片机的开发》,微信公众号:我的一九九三,时间:2021年12月16日;
- 《还在用keil做51单片机开发马?快来试试开源的SDCC吧》,微信公众号:STEM创造家,时间:2021年12月10日;
- 《CentOS7设置环境变量》(该篇博文在哔哩哔哩里有博主配套的视频讲解,强烈推荐观看!),博主:C语言技术网-码农有道,时间:2020年3月27日;
- 《一文带你学会Linux系统的变量》,微信公众号:生信喵实验柴,时间:2021年12月14日;
- 《如何设置与查看Linux系统中的环境变量》,微信公众号:良许,时间:2020年8月17日;
- 《Linux目录详解,软件应该安装到哪个目录》,博主:Deshun,时间:2019年6月13日。
文章更新时间记录
- 文章框架搭好;「2023.2.2.19 19:10」
- 九篇参考博文打列完毕;「2023.2.19 19:26」
- “安装开源编译器
SDCC
”一节完毕。「2023.2.19 21:07」 - “STC MCU ISP闪存工具
stcgal
的安装”一节完毕。「2023.2.19 21:25」 - “单片机代码的编译与测试”一节里的三小节完毕。「2023.2.20 13:33」
- “使用SDCC进行单片机程序编写的不同点”一节完成。「2023.2.20 13:53」
- “单片机效果展示”一节完成。「2023.2.20 18:43」
- “使用sdcc编译”该小节内增加了BIN文件相关内容。「2023.2.20 19:45」
- 文章首次发布于CSDN。「2023.2.21 12:20」
P.S.1 2022年12月下旬在别人的同类型的博文下了留言,如今自己在两个月也写了一篇。两个月,两个月,两年,两年,唉。「2023.2.20 19:47」