前言
STC单片机用Keil开发是很方便的,官方的例程也都是基于Keil的,奈何总是存在不能使用Keil进行开发的情况,比如没有购买Keil的正版授权,这就需要我们考虑使用其他的开发环境来代替Keil,vscode+platformio就是选择之一。
vscode+platformio的组合是有优点的,起码vscode作为编辑器比Keil的代码编辑功能强上百倍;但它也是有缺点的,比如相关的资料比较少,遇到问题解决起来可能比较麻烦。但是瑕不掩瑜,此方案还是不错的,我在使用过程中遇到的一些问题也记录在此,而且整个环境用到的工具也在不断优化中,相信后续会越来越好用。
本文整理了如何使用vscode+platformio创建STC8H1K08单片机的工程,如何移植官方库,以及编译和烧录过程中遇到的问题及解决办法。
环境版本介绍
PC操作系统:Win11
单片机:STC8H1K08
Platformio:Core 6.1.15,Home 3.4.4
SDCC:4.4.0 #14620
stcgal:@ 1.110.0 (1.10)
platformio工程创建
platformio目前已经支持STC8H单片机了,创建工程很方便。
- 启动platformio,新建工程。
- 选择对应的单片机和工程路径,等待工程创建完成。
- 工程创建后,目录结构如下。
- 编写代码
将.c文件放到src目录下,.h文件放到include目录下,如果使用第三方库的话放到lib目录下。
官方库的移植
关于STC单片机的开发,官方提供了便于开发的C语言库,但是是适用于Keil也就是C51编译器的,而platformio使用的是SDCC编译器,C51和SDCC对于C语言的支持标准是不同的,所以如果在platformio下想要使用官方提供的C语言库的话,需要做一些修改才行。可以参考一下从Keil迁移到SDCC。
一、首先,SDCC没有提供intrins.h 头文件及相应栈操作函数,需要自行创建,内容如下:
#ifndef _INTRINS_H_
#define _INTRINS_H_
/* warning: __push __pop 使用堆栈临时保存 sfr 数据,必需成对使用!
__push(x);
... // 保护代码块
__pop(x); //缺少无该语句编译不会出错,但运行错误!
*/
#define __push(x) __asm push _##x __endasm /* void _push_ (unsigned char _sfr); */
#define __pop(x) __asm pop _##x __endasm /* void _pop_ (unsigned char _sfr); */
#define _push_ __push /*兼容 keil c51*/
#define _pop_ __pop /*兼容 keil c51*/
/* 安全使用保护宏:
pushSfr(x);
... // 受保护代码块
popSfr(x); // 缺少无该语句编译出错,确保生成正确代码。
*/
#define pushSfr(x) do{
\
__push(x)
#define popSfr(x) __pop(x);\
}while(0)
#endif //_INTRINS_H_
二、其次,如果你的Keil代码中用到了头文件reg51.h/reg52.h
,那么在platformio下需要改为8051.h/8052.h
,如果vscode显示波浪线你看着不舒服的话(虽然不影响编译),可以配置一下SDCC头文件的路径,platformio默认安装的SDCC路径通常为:C:\Users\Administrator\.platformio\packages\toolchain-sdcc\include\mcs51
,配置方法有两种:
- 修改.vscode目录下的c_cpp_properties.json,在includePath下添加路径,比如:
"C:/Users/Administrator/.platformio/packages/toolchain-sdcc/include/mcs51",
"C:/Users/Administrator/.platformio/packages/toolchain-sdcc/include"
- 修改platform.ini文件,
lib_deps = C:/Users/Administrator/.platformio/packages/toolchain-sdcc/include/mcs51
三、在官方提供的库文件中,有一个STC8H.H
头文件,它包含了reg51.h/reg52.h
,所以我们也不使用8051.h/8052.h
,而是把STC8H.H
修改一下,使其适用SDCC编译器,比如将
sfr P0 = 0x80;
sbit P00 = P0^0;
改为
__sfr __at 0x80 P0 ;
__sbit __at 0x80 P00 ;
我将#define _nop_() __asm NOP __endasm
也放在这个文件里了,因为SDCC不支持_nop_()
,需要这个宏定义。
四、在引入官方提供的C语言库后,还需要做一些修改,比如将sbit,sfr,bit,code, xdata
改为__sbit,__sfr,__bit,__code, __xdata
,还有中断服务函数的定义,比如void uart() interrupt 4 using 0
改为void uart(void) __interrupt (4) __using (0)
(注意括号),类似这些其实就是C51和SDCC在C语言标准上的差异,遇到问题时上网查一下就可以解决。
编译
在完成库的移植后,直接进行编译就可以了,编译过程如下:
* 正在执行任务: C:\Users\23043036\.platformio\penv\Scripts\platformio.exe run
Processing STC8H1K08 (platform: intel_mcs51; board: STC8H1K08)
----------------------------------------------------------------------------------------------------------
Verbose mode can be enabled via `-v, --verbose` option
CONFIGURATION: https://docs.platformio.org/page/boards/intel_mcs51/STC8H1K08.html
PLATFORM: Intel MCS-51 (8051) (2.2.0) > Generic STC8H1K08
HARDWARE: STC8H1K08 11MHz, 1.25KB RAM, 8KB Flash
PACKAGES:
- toolchain-sdcc @ 1.40400.0 (4.4.0)
LDF: Library Dependency Finder -> https://bit.ly/configure-pio-ldf
LDF Modes: Finder ~ chain, Compatibility ~ soft
Found 0 compatible libraries
Scanning dependencies...
No dependencies
Building in release mode
Compiling .pio\build\STC8H1K08\src\STC8G_H_Delay.rel
Compiling .pio\build\STC8H1K08\src\STC8G_H_GPIO.rel
Compiling .pio\build\STC8H1K08\src\STC8G_H_NVIC.rel
Compiling .pio\build\STC8H1K08\src\STC8G_H_SPI.rel
Compiling .pio\build\STC8H1K08\src\STC8G_H_SPI_Isr.rel
Compiling .pio\build\STC8H1K08\src\STC8G_H_UART.rel
Compiling .pio\build\STC8H1K08\src\STC8G_H_UART_Isr.rel
Compiling .pio\build\STC8H1K08\src\main.rel
src\STC8G_H_SPI.c:62: warning 110: conditional flow changed by optimizer: so said EVELYN the modified DOG
src\STC8G_H_SPI_Isr.c:28: warning 158: overflow in implicit constant conversion
Linking .pio\build\STC8H1K08\firmware.hex
Checking size .pio\build\STC8H1K08\firmware.hex
Advanced Memory Usage is available via "PlatformIO Home > Project Inspect"
Flash: [======== ] 77.3% (used 6330 bytes from 8192 bytes)
====================================== [SUCCESS] Took 5.94 seconds ======================================
* 终端将被任务重用,按任意键关闭。
烧录及问题
platformio烧录STC单片机的程序,用的工具是stcgal,我使用串口进行程序烧写,这里遇到一个问题,烧录失败,日志如下:
* 正在执行任务: C:\Users\23043036\.platformio\penv\Scripts\platformio.exe run --target upload
Processing STC8H1K08 (platform: intel_mcs51; board: STC8H1K08)
----------------------------------------------------------------------------------------------------------
Verbose mode can be enabled via `-v, --verbose` option
CONFIGURATION: https://docs.platformio.org/page/boards/intel_mcs51/STC8H1K08.html
PLATFORM: Intel MCS-51 (8051) (2.2.0) > Generic STC8H1K08
HARDWARE: STC8H1K08 11MHz, 1.25KB RAM, 8KB Flash
PACKAGES:
- tool-stcgal @ 1.110.0 (1.10)
- tool-vnproch55x @ 1.0.220407
- toolchain-sdcc @ 1.40400.0 (4.4.0)
LDF: Library Dependency Finder -> https://bit.ly/configure-pio-ldf
LDF Modes: Finder ~ chain, Compatibility ~ soft
Found 0 compatible libraries
Scanning dependencies...
No dependencies
Building in release mode
Checking size .pio\build\STC8H1K08\firmware.hex
Advanced Memory Usage is available via "PlatformIO Home > Project Inspect"
Flash: [======== ] 76.3% (used 6251 bytes from 8192 bytes)
Configuring upload protocol...
AVAILABLE: stcgal
CURRENT: upload_protocol = stcgal
Looking for upload port...
Auto-detected: COM3
Uploading .pio\build\STC8H1K08\firmware.hex
Cycling power: done
Waiting for MCU: done
Target model:
Name: STC8H1K08
Magic: F734
Code flash: 8.0 KB
EEPROM flash: 4.0 KB
Target frequency: 11.058 MHz
Target BSL version: 7.3.12U
Target wakeup frequency: 35.825 KHz
Target ref. voltage: 1190 mV
Target mfg. date: 2021-03-18
Target options:
reset_pin_enabled=False
clock_gain=high
watchdog_por_enabled=False
watchdog_stop_idle=True
watchdog_prescale=256
low_voltage_reset=True
low_voltage_threshold=0
eeprom_erase_enabled=True
bsl_pindetect_enabled=False
por_reset_delay=long
rstout_por_state=high
uart1_remap=False
uart2_passthrough=True
uart2_pin_mode=push-pull
epwm_open_drain=True
program_eeprom_split=8192
Loading flash: 6251 bytes (Intel HEX)
Trimming frequency: 11.062 MHz
Switching to 19200 baud: done
Serial port error: read timeout
*** [upload] Error 1
====================================== [FAILED] Took 24.20 seconds ======================================
排查了一天,在stcgal的github上没有找到解决办法,最后在platformio的github issues下找到了。修改文件 C:\Users\23043036\.platformio\platforms\intel_mcs51\builder\main.py
,对于stc8,将stcgal_protocol改为auto,如下。注:-D表示显示日志,“-b”, 2400,指定串口波特率。
if upload_protocol == "stcgal":
f_cpu_khz = int(board_config.get("build.f_cpu").strip("L")) / 1000
stcgal_protocol = board_config.get("upload.stcgal_protocol")
if stcgal_protocol == 'stc8':
stcgal_protocol = 'auto'
env.Replace(
UPLOADER=join(platform.get_package_dir("tool-stcgal") or "", "stcgal.py"),
UPLOADERFLAGS=[
"-P",
stcgal_protocol,
"-p",
"$UPLOAD_PORT",
"-t",
int(f_cpu_khz),
"-a",
"-D"
],
UPLOADCMD='"$PYTHONEXE" "$UPLOADER" $UPLOADERFLAGS $SOURCE',
)
upload_actions = [
env.VerboseAction(env.AutodetectUploadPort, "Looking for upload port..."),
env.VerboseAction("$UPLOADCMD", "Uploading $SOURCE"),
]
先将单片机断电,然后点击platformio的upload按钮,日志显示:
* 正在执行任务: C:\Users\23043036\.platformio\penv\Scripts\platformio.exe run --target upload
Processing STC8H1K08 (platform: intel_mcs51; board: STC8H1K08)
----------------------------------------------------------------------------------------------------------
Verbose mode can be enabled via `-v, --verbose` option
CONFIGURATION: https://docs.platformio.org/page/boards/intel_mcs51/STC8H1K08.html
PLATFORM: Intel MCS-51 (8051) (2.2.0) > Generic STC8H1K08
HARDWARE: STC8H1K08 11MHz, 1.25KB RAM, 8KB Flash
PACKAGES:
- tool-stcgal @ 1.110.0 (1.10)
- tool-vnproch55x @ 1.0.220407
- toolchain-sdcc @ 1.40400.0 (4.4.0)
LDF: Library Dependency Finder -> https://bit.ly/configure-pio-ldf
LDF Modes: Finder ~ chain, Compatibility ~ soft
Found 0 compatible libraries
Scanning dependencies...
No dependencies
Building in release mode
Checking size .pio\build\STC8H1K08\firmware.hex
Advanced Memory Usage is available via "PlatformIO Home > Project Inspect"
Flash: [======== ] 77.3% (used 6330 bytes from 8192 bytes)
Configuring upload protocol...
AVAILABLE: stcgal
CURRENT: upload_protocol = stcgal
Looking for upload port...
Auto-detected: COM3
Uploading .pio\build\STC8H1K08\firmware.hex
Cycling power: done
到此处时给单片机上电,日志继续:
CURRENT: upload_protocol = stcgal
Looking for upload port...
Auto-detected: COM3
Uploading .pio\build\STC8H1K08\firmware.hex
Cycling power: done
<- Packet data: 46 B9 68 00 38 50 00 A8 BB 50 B4 00 02 FF FF BF BF FF 26 9F F7 20 73 55 00 F7 34 0C 8B F1 AF DC 0F 1F 20 FF 00 30 00 20 04 A6 21 03 18 32 FF 7B 2E 5A 8B A6 C4 F4 FF 17 55 16
Waiting for MCU: done
Protocol detected: stc8g
Target model:
Name: STC8H1K08
Magic: F734
Code flash: 8.0 KB
EEPROM flash: 4.0 KB
Target frequency: 11.058 MHz
-> Packet data: 46 B9 6A 00 18 00 08 00 00 FF 00 00 10 FF 10 00 20 FF 20 00 30 FF 30 05 46 16
Target BSL version: 7.3.12U
Target wakeup frequency: 35.825 KHz
Target ref. voltage: 1190 mV
Target mfg. date: 2021-03-18
Target options:
reset_pin_enabled=False
clock_gain=high
watchdog_por_enabled=False
watchdog_stop_idle=True
watchdog_prescale=256
low_voltage_reset=True
low_voltage_threshold=0
eeprom_erase_enabled=True
bsl_pindetect_enabled=False
por_reset_delay=long
rstout_por_state=high
uart1_remap=False
uart2_passthrough=True
uart2_pin_mode=push-pull
epwm_open_drain=True
program_eeprom_split=8192
Loading flash: 6330 bytes (Intel HEX)
<- Packet data: 46 B9 68 00 18 00 08 17 75 28 FD 17 75 28 FA 17 72 28 F7 17 78 28 FA 07 40 16
-> Packet data: 46 B9 6A 00 20 00 0C B0 00 B1 00 B2 00 B3 00 B4 00 B5 00 B6 00 B7 00 B8 00 B9 00 BA 00 BB 00 09 18 16
Target frequency: Target 11.059 MHz
<- Packet data: 46 B9 68 00 20 00 0C 23 BD 23 CF 23 E1 23 F3 24 0B 24 1A 24 2F 24 3B 24 41 24 4D 24 62 24 71 07 90 16
Adjusted frequency: 11.072 MHz(0.121%)
-> Packet data: 46 B9 6A 00 0E 01 00 00 FF CC 00 B4 98 03 90 16
<- Packet data: 46 B9 68 00 07 01 00 70 16
-> Packet data: 46 B9 6A 00 0B 05 00 00 5A A5 01 79 16
Switching to 115200 baud: done
<- Packet data: 46 B9 68 00 07 05 00 74 16
-> Packet data: 46 B9 6A 00 0B 03 00 00 5A A5 01 77 16
<- Packet data: 46 B9 68 00 0E 03 F7 34 C6 09 0F 95 AA 03 C1 16
-> Packet data: 46 B9 6A 00 4B 22 00 00 5A A5 02 00 06 02 17 74 75 81 6C 12 18 A9 E5 82 60 03 02 00 03 79 00 E9 44 00 60 1B 7A 00 90 18 BA 78 41 75 A0 03 E4 93 F2 A3 08 B8 00 02 05 A0 D9 F4 DA F2 75 A0 FF E4 78 FF F6 D8 FD 78 00 E8 44 00 1D 27 16
<- Packet data: 46 B9 68 00 08 02 54 00 C6 16
Erasing flash: done
Writing flash: 0%| | 0/6656 [00:00<?, ? Bytes/s]-> Packet data: 46 B9 6A 00 4B 02 00 40 5A A5 60 0A 79 01 75 A0 00 E4 F3 09 D8 FC 78 40 E8 44 03 60 0C 79 04 90 00 01 E4 F0 A3 D8 FC D9 FA 02 00 03 AF 82 7D 51 7E 04 1D BD FF 01 1E ED 4E 70 F7 DF F1 22 E5 82 FF 24 F8 50 04 75 82 FF 22 AC 20 CE 16
<- Packet data: 46 B9 68 00 08 02 54 00 C6 16
-> Packet data: 46 B9 6A 00 4B 02 00 80 5A A5 0A AD 0B AE 0C 8C 82 8D 83 8E F0 12 18 8D FB 24 FC 50 04 75 82 FF 22 EF 60 03 02 01 47 EB 70 21 74 01 2C F9 E4 3D FA 8E 03 89 82 8A 83 8B F0 12 18 8D F4 52 93 89 82 8A 83 8B F0 12 18 8D F4 52 1F 9D 16
<- Packet data: 46 B9 68 00 08 02 54 00 C6 16
-> Packet data: 46 B9 6A 00 4B 02 00 C0 5A A5 94 8C 82 8D 83 8E F0 12 18 8D FB BB 01 20 74 01 2C F9 E4 3D FA 8E 03 89 82 8A 83 8B F0 12 18 8D 42 93 89 82 8A 83 8B F0 12 18 8D F4 52 94 8C 82 8D 83 8E F0 12<