我们首先需要将Keil C51的代码转换为SDCC的代码。主要注意以下几点:
头文件:SDCC中通常使用#include <8051.h>或对应芯片的头文件,但这里我们使用STC8H,可能需要特定的头文件,但原代码使用的是reg51.h,我们可能需要替换为SDCC兼容的STC8头文件,或者使用通用方法。
特殊功能寄存器(SFR)的定义:在SDCC中,SFR的定义方式与Keil不同。SDCC使用__sfr、__sbit等关键字,或者使用绝对地址定位。
中断函数:SDCC中使用__interrupt关键字,并且中断号可能有所不同。
内存空间:在Keil中,使用code关键字表示程序存储区,而在SDCC中,使用__code或者const,并且访问方式可能不同。
位变量:SDCC支持位变量,但声明方式可能不同,使用__bit。
由于原代码中使用了STC8G1K08等芯片的内部参考电压地址,这些地址位于代码区(code),在SDCC中访问代码区需要使用__code关键字。
另外,原代码中定义了一个指向int的指针BGV,并将其指向代码区的某个地址。在SDCC中,我们需要将BGV声明为指向__code int的指针。
由于SDCC的标准库中没有intrins.h,但原代码中并没有使用该头文件中的函数,所以可以去掉。
我们假设使用SDCC编译STC8系列芯片,并且使用对应的头文件。但是,如果没有合适的头文件,我们可以使用绝对地址定义SFR。
下面我们开始转换:
步骤:
替换头文件:由于SDCC没有reg51.h,我们可以使用8051.h,但为了支持STC8的扩展SFR,我们需要自定义SFR。
定义SFR:使用__sfr定义AUXR以及PxM0、PxM1。
修改中断函数为SDCC格式。
修改BGV的声明,使用__code int *。
修改主函数中的初始化部分。
注意:SDCC中,中断函数使用__interrupt(中断号)的方式,且中断号可能与Keil不同。对于UART中断,在51系列中通常是中断4,但需要确认。
由于原代码是针对STC8G1K08,我们假设使用SDCC编译,并且使用large或huge模式,因为代码地址可能超过2K。
下面给出转换后的代码:
以下是转换后的 SDCC 代码:
- #include <8051.h>
- #include <stdint.h>
-
- #define FOSC 11059200UL
- #define BRT (65536 - FOSC / 115200 / 4)
-
- // 定义特殊功能寄存器
- __sfr __at (0x8E) AUXR;
- __sfr __at (0x93) P0M1;
- __sfr __at (0x94) P0M0;
- __sfr __at (0x91) P1M1;
- __sfr __at (0x92) P1M0;
- __sfr __at (0x95) P2M1;
- __sfr __at (0x96) P2M0;
- __sfr __at (0xB1) P3M1;
- __sfr __at (0xB2) P3M0;
- __sfr __at (0xB3) P4M1;
- __sfr __at (0xB4) P4M0;
- __sfr __at (0xC9) P5M1;
- __sfr __at (0xCA) P5M0;
-
- __bit busy;
- uint16_t __code *BGV; // 指向代码存储区的指针
-
- void UartIsr() __interrupt(4)
- {
- if (TI)
- {
- TI = 0;
- busy = 0;
- }
- if (RI)
- {
- RI = 0;
- }
- }
-
- void UartInit()
- {
- SCON = 0x50;
- TMOD = 0x00;
- TL1 = BRT;
- TH1 = BRT >> 8;
- TR1 = 1;
- AUXR = 0x40;
- busy = 0;
- }
-
- void UartSend(char dat)
- {
- while (busy);
- busy = 1;
- SBUF = dat;
- }
-
- void main()
- {
- P0M0 = 0x00;
- P0M1 = 0x00;
- P1M0 = 0x00;
- P1M1 = 0x00;
- P2M0 = 0x00;
- P2M1 = 0x00;
- P3M0 = 0x00;
- P3M1 = 0x00;
- P4M0 = 0x00;
- P4M1 = 0x00;
- P5M0 = 0x00;
- P5M1 = 0x00;
-
- // 根据芯片型号选择正确的地址
- BGV = (uint16_t __code *)0x1FF7; // STC8G1K08
- // BGV = (uint16_t __code *)0x3FF7; // Ai8H1K16
- // BGV = (uint16_t __code *)0x7FF7; // Ai8H8K32U
- // BGV = (uint16_t __code *)0xBFF7; // Ai8H8K48U
- // BGV = (uint16_t __code *)0xEFF7; // Ai8H8K60U
- // BGV = (uint16_t __code *)0xFDF7; // Ai8H8K64U
- // BGV = (uint16_t __code *)0x2FF7; // Ai8H1K12
- // BGV = (uint16_t __code *)0x43F7; // Ai8H1K17
- // BGV = (uint16_t __code *)0x5FF7; // Ai8H1K24
- // BGV = (uint16_t __code *)0x6FF7; // Ai8H1K28
- // BGV = (uint16_t __code *)0x83F7; // Ai8H1K33
-
- UartInit();
- ES = 1;
- EA = 1;
-
- // 读取内部1.19V参考信号源
- UartSend(*BGV >> 8); // 高字节
- UartSend(*BGV); // 低字节
-
- while (1);
- }
复制代码
**主要修改点:**
1. **头文件**:
- 替换 `reg51.h` 为 `8051.h`
- 替换 `intrins.h` 为 `stdint.h`(用于标准整数类型)
2. **SFR 定义**:
- SDCC 使用 `__sfr __at (地址)` 语法定义特殊功能寄存器
- 所有扩展的 SFR 都需要用这种方式定义
3. **位变量**:
- SDCC 使用 `__bit` 定义位变量
4. **代码区指针**:
- Keil C51: `int code *`
- SDCC: `uint16_t __code *`
- 使用 `uint16_t` 确保处理 16 位数据
5. **编译命令**:
```bash
sdcc -mmcs51 --model-large --stack-auto main.c
```
- `--model-large`:适合较大的 STC8 系列芯片
- `--stack-auto`:启用自动栈管理
6. **生成的文件**:
- SDCC 会生成多个文件,主要是 `main.ihx`(Intel HEX 格式)
- 可以使用 `packihx` 转换为标准 HEX 文件:
```bash
packihx main.ihx > main.hex
```
**注意事项:**
1. **芯片型号选择**:根据实际使用的芯片取消注释对应的地址行
2. **头文件路径**:确保 SDCC 能找到 `8051.h` 头文件
3. **内存模型**:对于 STC8 系列,通常需要 `--model-large` 或 `--model-huge` 选项
4. **中断向量**:SDCC 的中断向量表与 Keil 不同,但 UART 中断号 4 是通用的
这个转换后的代码应该可以在 SDCC 中正常编译和运行,用于读取 STC8 系列芯片的内部参考电压。
|