TA的每日心情 | 开心 2024-3-23 15:15 |
---|
签到天数: 21 天 [LV.4]偶尔看看III
注册会员
- 积分
- 181
|
前言
想要使用开源的SDCC来编译一些简单的51单片机程序,但不想建立繁多的工程文件夹?在线工具对网络环境要求高?头文件用了Keil的关键字?这个自制的VsCode插件或许可以解决你的问题。
功能介绍
- 文件标签右键菜单“使用SDCC编译(Ctrl+F9)”,快捷编译
- 编辑区域右键菜单“Keil语法转SDCC”,快速转换语法
- 编辑区域右键菜单“转到汇编代码”,快速查看指定语句编译后的汇编码与机器码
- 展示SDCC编译得到的空间占用分布情况(.mem文件)
安装与使用
- 安装SDCC编译器,并添加到PATH。
- 安装VSCode,在VSCode中搜索安装“C/C++”(微软官方)、“51forSDCC”插件(自制)。
- 在VSCode中打开想要存放代码的文件夹,建立头文件、以“main”开头的.c文件等文件,开始编码。所有代码需要是GBK编码格式。
- 编码完成后,保存文件并编译,使用STC-ISP烧录hex文件。由于STC-ISP只有Windows版本,本插件也因此仅考虑Windows兼容性,并且要求VSCode的终端使用默认的PowerShell,而不是cmd。
说明
- SDCC的帮助文档位于:C:\Program Files\SDCC\doc\sdccman.pdf(默认安装位置)
- VSCode的工作文件夹中,文件名以“main”或“test”开头的.c文件视为主程序(需要含有main函数),其他.c文件视为库文件。本插件将必要的的文件编译、链接在一起,在“build”文件夹下生成与主程序文件同名的hex文件。因此,共享相同库的简单主程序可以放在一个文件夹下,不需要建立工程,尤其适合单文件的简单代码。
- 在扩展设置中,可以添加额外的编译命令行。SDCC默认将变量储存在data区中(即“--model-small”),可改用“--model-medium”将变量默认储存到pdata区,或改用“--model-large”将变量默认储存到xdata区。一般不需要修改,因为可以手动修饰较大的变量,将其放到pdata或xdata区域,而剩余的变量保持在默认的data区,获得较快的速度和较短的代码。
- SDCC的变量修饰关键字为:__code、__data、__idata、__pdata、__xdata、__bit,可根据实际需求修饰,如将不频繁使用、较大的变量放在pdata或xdata区。内存占用与代码长度会在编译成功后显示。
- 只要一个.c文件中实现的函数被用到至少一个,则SDCC就会将该.c文件中所有实现的函数链接到最终二进制文件中,造成代码长度增大。因此,编写库文件时应尽量将可能不会同时用到的函数拆分到不同.c文件中,极端情况下甚至可以让一个函数对应一个.c文件。
- SDCC默认使用较新的C语言标准,不支持C++,变量不强制定义在函数开头,无参函数需要使用(void)修饰(如main函数)。
- SDCC的中断函数需要在main函数所在文件中声明,格式为:void 名称(void) __interrupt(中断号)
- SDCC只支持float浮点数,不支持double,书写浮点常量时注意以f结尾。
- SDCC可使用__asm__("汇编代码")实现内联汇编,如__asm__("nop\nnop");
- 如果找不到头文件,可添加包含文件目录“C:\Program Files\SDCC\include”。某些关键字可能会有下划线报错,不理睬即可。
- SDCC的printf对于小容量单片机来说太过笨重,可以使用功能较少的printf_fast_f(带浮点)、printf_fast甚至printf_tiny代替。需要包含stdio.h,并自行提供一个标准的putchar函数,原型为:int putchar(int ch)。不同printf的对比表格:
SDCC自带的不同printf函数
这里我以STC8G1K08为例,给出一个初始化串口输出以使用printf的例子。定时器1既用作波特率发生器也兼用作嘀嗒计时器,因此无需计算指令周期数即可实现延时。
#include "STC8G.H" // 直接由STC-ISP提供的头文件经过“Keil语法转SDCC”转换得到
#include <stdint.h>
#include <stdio.h>
#define FOSC 11059200UL
#define BAUD 115200UL
#define LOAD (65536U - FOSC / BAUD / 4)
void UART_Init(void) {
SCON = 0x50;
TMOD = 0x00, AUXR = 0x40;
TL1 = LOAD & 0xff, TH1 = LOAD >> 8;
TR1 = 1, ET1 = 1, EA = 1;
}
int putchar(int ch) {
SBUF = ch;
while (!TI)
;
TI = 0;
return ch;
}
uint16_t systick_10ms = 0, systick = 0;
void Timer1_ISR(void) __interrupt(3) {
if (++systick == BAUD * 4 / 100) {
++systick_10ms;
systick = 0;
}
}
void delay(uint16_t ms) {
uint16_t end = systick_10ms + ms / 10;
while (systick_10ms < end)
;
}
void main(void) {
P3M1 = 0b00000000, P3M0 = 0b00000000; // 准双向口
UART_Init();
delay(1000);
int i = 0;
while (1) {
printf_tiny("%d\n", i++);
delay(1000);
}
}
以上面的代码为例,编译后,在“TL1 = LOAD & 0xff, TH1 = LOAD >> 8;”这句代码上右击,选择“转到汇编代码”,可以看到以下几行汇编码: 636 ; main_simple_printf.c:12: TL1 = LOAD & 0xff, TH1 = LOAD >> 8;
000009 75 8B E8 [24] 637 mov _TL1,#0xe8
00000C 75 8D FF [24] 638 mov _TH1,#0xff
这说明SDCC可以自动展开简单的常量表达式,可以通过宏定义自动适配IRC频率和波特率,而不需要手动重新计算或在运行时计算定时器装载值。
编译后显示的内存分布为:
Internal RAM layout:
0 1 2 3 4 5 6 7 8 9 A B C D E F
0x00:|0|0|0|0|0|0|0|0|a|a|a|a|b|Q|Q|S|
0x10:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
0x20:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
0x30:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
0x40:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
0x50:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
0x60:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
0x70:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
0x80:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
0x90:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
0xa0:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
0xb0:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
0xc0:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
0xd0:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
0xe0:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
0xf0:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
0-3:Reg Banks, T:Bit regs, a-z:Data, B:Bits, Q:Overlay, I:iData, S:Stack, A:Absolute
Stack starts at: 0x0f (sp set to 0x0e) with 241 bytes available.
No spare internal RAM space left.
Other memory:
Name Start End Size Max
---------------- -------- -------- -------- --------
PAGED EXT. RAM 0 256
EXTERNAL RAM 0 65536
ROM/EPROM/FLASH 0x0000 0x028a 651 65536
其中,16×16的矩阵表示了idata区域中每个字节的作用,最后表格的Size列分别展示了PDATA、XDATA、FLASH占用的空间。由于编译速度很快,可以对比不同写法代码的空间占用,SDCC提供的该编译信息使得优化空间占用变得更加容易。
希望该VSCode插件对大家有所帮助!
|
3
喜欢他/她就送朵鲜花吧,赠人玫瑰,手有余香!
-
+2
楼主威武~
-
+1
楼主威武~
-
+1
楼主威武~
|