STC系列8位MCU在Windows下的开发


STC系列51单片机

简介

都是8051衍生的8位单片机, STC单片机有89/90/10/11/12/15这几个大系列, 每个系列的特点如下

  • 89系列是传统的8051单片机, 烧录方法有区别, 但是功能上可以和AT89系列兼容, 属于12T单片机
  • 90系列是89系列的改进型, 12T单片机
  • 10和11系列是1T单片机, 有PWM, 4态IO接口, EEPROM等功能, 但都没有ADC
  • 12系列是增强型功能的1T单片机, 型号后缀AD的带ADC, 后缀S2的除了ADC还带双串口
  • 15系列是最新的产品, 内部集成了高精度R/C时钟, 不需要外部晶振

STC89C52参数

STC89C52和STC89C51的区别仅在于Flash大小, C51为4K而C52为8K. 都有多种封装, 常见的是体积较大的DIP40宽体双列

  • Flash: 8K bytes
  • RAM: 512 bytes
  • 内置4KB EEPROM
  • 32-bit I/O
  • 看门狗定时器, MAX810复位电路
  • 3个16-bit定时器
  • 4个外部中断, 一个7向量4级中断结构和全双工串行口
  • 最高运作频率35MHz, 6T/12T可选
  • VCC是5V, 不要高于这个电压.

还有规格更高的STC89C516DR, 这个有62K的flash和1280byte的RAM. 如果需要ADC, 可以选 STC12C5A60S2 系列, 1T型的指令时钟速度比普通STC89系列(12T)快, 做定时时要注意.

晶振

  • 内部不带振荡源, 必须外接晶振
  • 采用11.0592MHz,或22.1184MHz,可方便得到串口通讯的标准时钟.
  • 如果使用12MHz, 对应定时器为12分频, 一个机器周期为1 微秒,便于做精确定时.

普通应用一般都选11.0592MHz晶振, 做毫秒和秒的定时也能做到很精确.

硬件准备

  • C51最小开发板
  • 一个USB2TTL的转接卡
  • 用于查看输出的LED+1K限流电阻

Windows下的开发

软件部分

需要准备用于烧录的STC-ISP软件, 以及用于编写编译代码的Keil C51软件

STC-ISP安装

用简化版(tiny结尾的那个), 这个版本不会跟你要管理权限. 解压即可不需安装, 界面非常紧凑. STC这个公司的网站和软件界面都很有特点, 深受低分辨率屏幕影响的设计方式, 界面上除了字就是字. 浓浓的乡镇企业风.

Keil C51安装

安装时, 默认安装到与Keil MDK相同的目录C:\Keil_V5, 如果之前已经安装了Keil MDK, 可以使用同一目录, 与Keil MDK是可以共存的. 安装完之后在license里可以看到有C51的license记录

安装STC设备库

根据STC-ISP的使用说明, 将STC库文件安装到Keil C51环境中.

  • 关闭Keil MDK软件
  • 打开STC-ISP
  • 点击右侧标签面板中的Keil ICE Setting, 点击Add MCU type to Keil, Add STC ICE driver to Keil这个按钮
  • 然后定位到C:\Keil_v5目录, 完成安装

检查

  • 查看C:\Keil_v5\UV4\目录下是否有stc.cdb文件, 判断是否添加完成
  • 查看C:\Keil_v5\C51\INC\目录下是否有STC目录, 这个目录下是STC芯片的头文件
  • 重启Keil MDK后, 在File->Device Database中选择STC MCU Database可以看到STC下的单片机型号列表

烧录

接线

USB2TTL STC89C52
VCC P40 VCC
GND P20 GND
TX P10 RxD
RX P11 TxD

烧录

STC单片机使用的是ISP(In System Program)烧录方式, 其原理是在单片机内部固化一段ISP代码, 上电时检测是否有连续的d字符, 如果检测到则进入ISP准备阶段, 如果超时没有收到则执行用户代码区. 若进入ISP准备阶段, 根据STC定义的协议接收数据帧, 最后完成程序的擦除、写入. 在ISP准备阶段若未收到数据帧, 则超时退出ISP, 执行用户代码区.

STC-ISP的使用说明

  • 运行STC-ISP
  • 选择烧录芯片对应的型号
    • STC89C52RC/LE52RC, 如果不是RC, 则选择 STC89C52
    • 如果型号选择不正确, 在Check MCU那一步会一直卡在那里
  • 选择USB2TTL对应的COM口
  • 点击Open Code File 加载烧录程序
  • 设置烧录选项
  • 点击Download/Program按钮

如果之前已经连线, 此时STC-ISP的日志窗口会提示Checking target MCU ... , 按Reset开关不能进入烧录, 需要重新上电才会开始烧录. 显示信息如下

Checking target MCU ... 
  MCU type: STC89C52RC/LE52RC
  F/W version: 3.2C

Current H/W Option:
  . Current clock frequency: 11.018MHz
  . System use 12T mode
  . Oscillator gain is HIGH
  . Any reset source can stop WatchDog if WatchDog timer is running
  . Internal XRAM is ENABLE  . ALE pin behaves as ALE function pin
  . Do not detect the level of P1.0 and P1.1 next download
  . Do not erase user EEPROM area at next download

  MCU type: STC89C52RC/LE52RC
  F/W version: 3.2C


Re-handshaking ... Successful			[0.625"]
Current Baudrate: 115200
Erasing MCU flash ...  OK !		[0.188"]
Programming user code ... OK !		[0.953"]
Programming OPTIONS ... OK !		[0.031"]

H/W Option upgrade to:
  . Current clock frequency: 11.018MHz
  . System use 12T mode
  . Oscillator gain is HIGH
  . Any reset source can stop WatchDog if WatchDog timer is running
  . Internal XRAM is ENABLE  . ALE pin behaves as ALE function pin
  . Do not detect the level of P1.0 and P1.1 next download
  . Do not erase user EEPROM area at next download

  MCU type: STC89C52RC/LE52RC
  F/W version: 3.2C


  Complete !(2021-06-30 21:54:26)
  • 如果F/W version是3.2C, 会弹出对话框, 提示这是一个翻新的芯片, 可以忽略. 4.2C的不会弹出此提示.
  • STC12C5A60S2 系列在烧录时会显示MCU ID, STC89C系列不会

Keil C51代码结构

与STM32项目比, C51的项目的结构简单多了. 只需要添加一个reg52.h的头文件, 剩下的就是自己随意组合. 这个头文件也只是命名了一些常量.

创建项目的步骤比较简单:

  • 运行Keil MDK
  • 新建项目, 找一个目录将项目文件保存
  • 选择设备
    • 对于STC89C52, 定位到STC89C52RC Series
    • 对于STC89C516RD+, 定位到STC89C58RD+ Series
    • 对于STC12C5A56S2, 定位到STC12C5A60S2 Series
    • 这些都可以使用reg52.h作为头文件
  • 中途会提示你是否要保存startup.a51, 选择是
  • 新建C文件, 写入代码
  • 编译

示例代码

#include <reg52.h>

typedef unsigned int u16;
typedef unsigned char u8;

sbit led0 = P0^0;
sbit led1 = P0^1;
sbit led2 = P0^2;
sbit led3 = P0^3;

void delay(u16 i) {
	while(i--);
}
void main() {
  while(1) {
    led0 = 0;
    led1 = 0;
    led2 = 0;
    led3 = 0;
    delay(500000);
    led0 = 1;
    led1 = 1;
    led2 = 1;
    led3 = 1;
    delay(500000);
  }
}

对于STC89C52RC, 可以改成#include <STC89C5xRC.H>, 对于STC12C5A60S2系列, 可以改成#include <STC12C5A60S2.H>

这个代码在 STC12C5AxxS2上运行, LED闪烁速度比在STC89C52RC上运行快很多.

常见问题

SBIT 单Bit, Singl Bit

sbit这个类型定义了SFR中的一个bit, 使用操作符^, 这里是容易引起疑惑的一个地方, 这个符号仅仅在代码变量声明的地方可用, 代表了SFR中这个bit的位置, 在程序当中, 这个符号才是标准的bit异或操作符(XOR Operator). The character ^ is used to denote the bit position in the byte address of the SFR. This syntax is only valid for Declaration code lines. If used inside the program, then the ^ operator is the standard bitwise xor operator from the standard C language (not specific to C51).

//方式1和2: 前面的sfr-name/sfr-address是其基础地址, 一定是要可以被8整除的, 例如0xD0, 0xA8,  后面的bit-position取值可以是0~7
sbit name = sfr-name ^ bit-position;
sbit name = sfr-address ^ bit-position;

//方式3: 必须是0x80-0xFF之间的一个值, 例如0xD2, 0xD7, 0xAF
sbit name = sbit-address;

其中

  • name 变量名
  • sfr-name 已经定义的SFR变量
  • bit-position 在SFR变量中的位置
  • sfr-address SFR的地址
  • sbit-address 此bit的地址

在8051应用中经常需要直接访问SFR中某一个位的信息, 这种情况就可以使用sbit. 例如:

sbit EA = 0xAF;

上面代码定义了一个sbit类型的变量EA, 其地址在0xAF. 在8051中这是中断开启寄存器中的enable all位的地址.

注意: 使用sbit访问的对象存储通常认为是little endian (LSB first), 如果使用sbit访问标准类型的数据时要留意.

注意:

  1. 不是所有SFR都可以按位寻址, 只有地址能被8整除的SFR才能, 即低位必须是0或8. 计算SFR的按位地址, 0xC8^6 = 0xC8 + 6 = 0xCE.
  2. sbit只能在函数外定义.

SFR - 特殊功能寄存器(Special Function Register)

在keil.com上有说明 https://www.keil.com/support/man/docs/c51/c51_le_sfrs.htm

sfr常用于定义寄存器地址, 对应一个8 bit volatile的值. 用法为

sfr name = address;

其中

  • name SFR的名称
  • address SFR的地址

SFR变量的定义和其他C变量一样, 区别仅在于不使用char或者int, 例如

sfr P0 = 0x80;    /* Port-0, address 80h */
sfr P1 = 0x90;    /* Port-1, address 90h */
sfr P2 = 0xA0;    /* Port-2, address 0A0h */
sfr P3 = 0xB0;    /* Port-3, address 0B0h */

P0, P1, P2 和 P3 都是SFR的声明和定义, 等号后面的值必须是8位数值, 8051支持的SFR地址通常为0x80-0xFF. 而NXP 80C51MX提供额外的SFR地址区间0x180-0x1FF. 注意, SFR变量不能定义在函数中, 而必须定义在主代码中, SFR变量永远是volatile的, 编译器不会去优化这种类型的变量的访问.

sfr16 占用两个内存单元, 值域为 0~65535. sfr16 和 sfr 一样用于操作特殊功能寄存器, 不一样的是它用于操作占两个字节的寄存器, 例如定时器 T0 和 T1.

C51寄存器的介绍 http://www.51hei.com/mcuteach/245.html

Flash和EEPROM的区别

EEPROM也叫 E2PROM, 称为电可擦可编程只读存储器, 和EEPROM类似, 写上去的东西也能擦掉重写, 但它要方便一些, 不需要光照, 只要用电就能擦除或者重新改写数据, 方便许多, 而且寿命也很长(几万到几十万次).

FLASH 闪存, 属于EEPROM的改进产品, 最大特点是必须按块(Block)擦除(每个区块的大小不同厂家的产品有不同的规格), 而EEPROM则可以一次只擦除一个字节(Byte). FLASH现在常用于大容量存储, 例如U盘.

C51的变量

c51编译器中int 和 short 相同,float 和 double 相同, 具体定义

类型 宽度 取值范围
unsigned char 1字节 0~255
signed char 1字节 -128~+127
unsigned int 2字节 0~65535
signed int 2字节 -32768~+32767
unsigned long 4字节 0~4294967295
signed long 4字节 -2147483648~+2147483647
float 4字节 -1.175494E-38~+3.402823E+38
指针 1-3字节 对象的地址
bit 0 或 1
sfr 1字节 0~255
sfr16 2字节 0~65535
sbit 0 或 1

C51中定义一个变量的格式如下

[存储种类] 数据类型 [存储器类型] 变量名
  • 在定义格式中除了数据类型变量名是必要的, 其它都是可选项
  • 存储种类有四种: 自动(auto), 外部(extern), 静态(static)和寄存器(register). 缺省类型为auto.
  • 数据类型即变量类型
  • 存储器类型指定该变量在单片机硬件系统中所使用的存储区域, 并在编译时准确的定位. 注意在AT89c51芯片中RAM只有低128位, 80H-FFH的高128位在52芯片中才有用, 并和特殊寄存器地址重叠.

把最常用的命令如循环计数器和队列索引放在内部数据区能显著的提高系统性能, 变量的存储种类与存储器类型是完全无关的.

C52的RAM分块和寻址

STC89C52 共有 512 字节的 RAM, 定义的变量都是直接存在 RAM 里边的. 但是这 512 字节的 RAM是分块的, 块与块之间在物理结构和用法上有区别.

RAM 分为片内 RAM和片外 RAM

  • 片内 RAM
    标准 51 的片内 RAM 地址从 0x00H~0x7F 共 128 个字节,而现在用的 51 系列都带扩展片内 RAM,即 RAM 从 0x00 - 0xFF 共 256 个字节.
  • 片外 RAM
    最大可以扩展到 0x0000~0xFFFF 共 64K 字节.
  • 片内 RAM 和片外 RAM 的地址不是连续的,片内从 0x00 开始, 片外也是从 0x0000 开始.
  • 片内和片外的区分来自于早期的 51 单片机,分别指在芯片内部和芯片外部,但现在几乎所有的 51 单片机(包括STC89C52)芯片内部都集成了片外 RAM, 很少用到真正的芯片外扩展

以下是几个 Keil C51 中的关键字, 代表了 RAM 不同区域

  • data: 片内RAM直接寻址区, 从00 - 7F
    定义一个变量 a, 可以这样unsigned char data a=0, 在 Keil 默认设置下,data是默认的可以省略. data 区域 RAM 的访问在汇编语言中用的是直接寻址, 执行速度是最快的.
  • bdata: 片内RAM位寻址区, 从20 - 2F这块地址的16个字节共128个可寻址位, 位地址从00 - 7F
    例如
unsingned char bdata sta; // 8位的数据sta
sbit RX_DR = sta^6;  //把 8位中的第6位定义为RX_DR, 下同
sbit TX_DS = sta^5;
sbit MAX_RT = sta^4;
  • idata: 片内RAM间接寻址区, 从 00-FF
    data 是 idata 的一部分. 定义成 idata,不仅仅可以访问 data 区域,还可以访问 80-FF 的范围,访问idata的时候用的是通用寄存器间接寻址, 速度较 data会慢一些, 平时大多数情况下不太希望访问 80-FF, 这块通常用于中断与函数调用的堆栈, 所以在绝大多数情况下, 使用内部 RAM 只用 data 就可以了.
  • pdata:片外 RAM 从 00-FF
    使用 pdata 定义的变量存到了外部 RAM 的 00-FF 的地址范围, 这块地址的访问和 idata 类似, 都是用通用寄存器间接寻址
  • xdata:片外 RAM 从 0000 - FFFF
    pdata 是 xdata 的一部分. 定义成 xdata, 可以访问的范围更广泛, 从 0 到 64K 的地址都可以访问到, 但是它需要使用 2 个字节寄存器DPTRH 和 DPTRL 来进行间接寻址,速度最慢, STC12C5A60S2系列的头文件中就用到了这个部分

STC89C52的寻址

STC89C52共有 512 字节的 RAM, 分为 256 字节的片内 RAM 和 256 字节的片外RAM. 一般情况下使用 data 区域, data 不够用了就用 xdata, 如果希望程序执行效率尽量高一点,就使用 pdata 关键字来定义.

复位后的各寄存器初始

复位后CPU状态

PC:  0000H         TMOD: 00H
Acc: 00H           TCON: 00H
B:   00H           TH0:  00H
PSW: 00H           TL0:  00H
SP:  07H           TH1:  00H
DPTR:0000H         TL1:  00H
P0-P3:FFH          SCON: 00H
IP:  ×××00000B     SBUF: 不定
IE:  0××00000B     PCON: 0×××0000B

注意P0 - P3是高位

startup.a51文件的作用

80C51在电源重置(Power On Reset)后执行的第一个程序模块并不是主程序main(), 而是一个KEIL-C51标准链接库中的startup.a51程序模块.

startup.a51的主要工作, 是把包含idata, xdata, pdata在内的内存区块清除为0, 并且初始化递归指针. 在startup.a51执行完成后, 接着被执行的仍然是一个KEIL-C51标准链接库中的init.a51程序模块. init.a51的主要作用, 是初始化具有非零初始值设定的变量.

在完成上述的初始化之后, 80C51才会开始执行main()程序.

参考


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM