zoukankan      html  css  js  c++  java
  • 51单片机(STC89C52)在Ubuntu下的开发

    简介

    都是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, 不要高于这个电压.

    如果需要ADC, 可以选 STC12C5A60S2 系列, 1T型的指令时钟速度比普通STC89系列(12T)快, 做定时时要注意.

    硬件准备

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

    在Ubuntu20.04下的开发

    软件部分

    安装sdcc

    Ubuntu20.04自带的sdcc版本为3.8.0, 所以打算自行编译安装. 先阅读sdcc的安装说明, 在 http://sdcc.sourceforge.net/doc/sdccman.pdf

    1. 前往 https://sourceforge.net/projects/sdcc/files/sdcc/4.1.0/ 下载最新的4.1.0源码.
    2. 解压tar -xvjf sdcc-src-4.1.0.tar.bz2
    3. 配置./configure, 过程中提示gputils需要安装, 通过apt install gputils安装, 再次./configure未再报错, 但是提示这个gputils比较旧, 有些设备不支持, 先忽略
    4. 编译make, 过程中提示缺texinfo, 通过apt install texinfo安装, 然后再make. 需要说一下的是编译时间很长, 如果仅仅需要编译C51, 可以在配置时禁掉其他一些不需要的芯片.
    5. 安装sudo make install

    检查和测试安装好的sdcc

    1. 执行sdcc --version看看输出是否正确, 执行sdcc --print-search-dirs查看库文件的位置. 默认的8051的库文件位置为/usr/local/share/sdcc/include/mcs51/
    2. 写一段代码test001.c,
    char test;
    
    void main(void) {
      test = 0;
    }
    

    用sdcc编译, 如果生成结果文件正常没有报错, 就说明安装没问题

    # 这一步会产生test001.asm等文件
    sdcc -c test001.c
    # 这一步会产生test001.ihx等文件
    sdcc test001.c
    

    安装stcgal

    根据Github上项目首页的说明, 直接用pip3 install stcgal安装, 然后执行stcgal -h查看输出

    编写代码并用sdcc编译

    编写一个test002.c, 通过控制占空比让P0.7上的LED产生呼吸灯的效果.

    • 8052.h是sdcc自带的通用的C52头文件, 不是STC89Cxx的定制头文件
    • 需要STC的头文件, 对应STC89C52, 可以用stc89.h; 对应STC12C5A60S2, 可以用stc12.h
    #include <8052.h>
    
    #define Led10 P0_7
    typedef unsigned int u16;
    
    int atime = 64;
    
    void delay(u16 pms) {
      u16 x, y;
      for (x=pms; x>0; x--) {
        for (y=11; y>0; y--);
      }
    }
    
    void ledfade(u16 i) {
      Led10 = 0;
      delay(i);
      Led10 = 1;
      delay(atime-i);
    }
    
    int main(void) {
      u16 a, b;
      while(1) {
        for (a=0; a<atime; a++) {
          for (b=0; b < (atime - a)/4; b++) {
            ledfade(a);
          }
        }
        for (a=atime; a>0; a--) {
          for (b=0; b < (atime - a)/4; b++) {
            ledfade(a);
          }
        }
      }
    }
    

    编译有两种方式

    • 加上-m<port>参数, 对应89C52/12C5A60S2, 用-mmcs51, 如果是Makefile, 加到CCFLAG里面
    • 不加参数, 在头文件中指定路径, 例如#include <mcs51/8052.h>

    这是使用参数的方式

    sdcc -mmcs51 test002.c
    

    烧录

    烧录使用stcgal, 这个页面下有详细的使用方法
    对于STC89C52使用-P stc89, 对于STC12C5A60S2系列, 使用-P stc12

    stcgal -P stc89 test002.ihx 
    
    Waiting for MCU, please cycle power: done # 这里要关闭再打开电源
    Target model:
      Name: STC89C52RC/LE52R
      Magic: F002
      Code flash: 8.0 KB
      EEPROM flash: 6.0 KB
    Target frequency: 11.010 MHz
    Target BSL version: 3.2C
    Target options:
      cpu_6t_enabled=False
      bsl_pindetect_enabled=False
      eeprom_erase_enabled=False
      clock_gain=high
      ale_enabled=True
      xram_enabled=True
      watchdog_por_enabled=False
    Loading flash: 243 bytes (Intel HEX)
    Switching to 19200 baud: checking setting testing done
    Erasing 2 blocks: done
    Writing flash: 640 Bytes [00:00, 1844.10 Bytes/s]                                             
    Setting options: done
    Disconnected!
    

    烧录完就会自动运行. 默认的波特率为19200, 写入较慢, 对于STC89C52RC可以直接使用115200的波特率, 用-b参数指定

    stcgal -P stc89 -b 115200 test002.ihx
    

    如果同时有多个com口, 用-p指定端口

    stcgal -P stc89 -b 115200 dist/89/89.hex -p /dev/ttyUSB1
    

    使用-D参数能显示出串口的交互信息

    stcgal -D -P stc89 -b 115200 test002.ihx 
    Waiting for MCU, please cycle power: <- Packet data: 46 B9 68 00 1C 00 0A 76 0A 72 0A 76 0A 72 0A 76 0A 72 0A 76 0A 72 32 43 FD F0 02 82 5A 16
    done
    Target model:
      Name: STC89C52RC/LE52R
      Magic: F002
      Code flash: 8.0 KB
      EEPROM flash: 6.0 KB
    Target frequency: 11.010 MHz
    Target BSL version: 3.2C
    Target options:
      cpu_6t_enabled=False
      bsl_pindetect_enabled=False
      eeprom_erase_enabled=False
      clock_gain=high
      ale_enabled=True
      xram_enabled=True
      watchdog_por_enabled=False
    Loading flash: 337 bytes (Intel HEX)
    Switching to 115200 baud: checking -> Packet data: 46 B9 6A 00 0C 8F FF FD 00 06 A0 81 28 16
    <- Packet data: 46 B9 68 00 0C 8F FF FD 00 06 A0 81 26 16
    setting -> Packet data: 46 B9 6A 00 0B 8E FF FD 00 06 A0 A5 16
    <- Packet data: 46 B9 68 00 0B 8E FF FD 00 06 A0 A3 16
    testing -> Packet data: 46 B9 6A 00 0C 80 00 00 36 01 F0 02 1F 16
    <- Packet data: 46 B9 68 00 06 80 EE 16
    -> Packet data: 46 B9 6A 00 0C 80 00 00 36 01 F0 02 1F 16
    <- Packet data: 46 B9 68 00 06 80 EE 16
    -> Packet data: 46 B9 6A 00 0C 80 00 00 36 01 F0 02 1F 16
    <- Packet data: 46 B9 68 00 06 80 EE 16
    -> Packet data: 46 B9 6A 00 0C 80 00 00 36 01 F0 02 1F 16
    <- Packet data: 46 B9 68 00 06 80 EE 16
    done
    Erasing 2 blocks: -> Packet data: 46 B9 6A 00 0D 84 02 33 33 33 33 33 33 2F 16
    <- Packet data: 46 B9 68 00 06 80 EE 16
    done
    -> Packet data: 46 B9 6A 00 8C 00 00 00 00 00 00 80 02 00 06 02 00 AC 75 81 09 12 01 4D E5 82 60 03 02 00 03 79 00 E9 44 00 60 1B 7A 00 90 01 51 78 01 75 A0 00 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 60 0A 79 01 75 A0 00 E4 F3 09 D8 FC 78 00 E8 44 00 60 0C 79 00 90 00 01 E4 F0 A3 D8 FC D9 FA 75 08 40 75 09 00 02 00 03 AE 82 AF 83 EE 4F 60 14 7C 0B 7D 00 1C BC FF 01 1D EC 4D 70 F7 1E BE FF FB 16
    <- Packet data: 46 B9 68 00 07 80 85 74 16
    Writing flash:   0%|                                              | 0/512 [00:00<?, ? Bytes/s]-> Packet data: 46 B9 6A 00 8C 00 00 00 00 80 00 80 01 1F 80 E8 22 AE 82 AF 83 C2 87 8E 82 8F 83 C0 07 C0 06 12 00 68 D0 06 D0 07 D2 87 AC 08 AD 09 EC C3 9E F5 82 ED 9F F5 83 02 00 68 7E 00 7F 00 AC 08 AD 09 C3 EE 9C EF 9D 50 45 7C 00 7D 00 AA 08 AB 09 EA C3 9E FA EB 9F C3 13 CA 13 CA C3 13 CA 13 CA FB C3 EC 9A ED 9B 50 1E 8E 82 8F 83 C0 07 C0 06 C0 05 C0 04 12 00 85 D0 04 D0 05 D0 06 D0 07 0C BC 00 C9 0D 80 C6 0E BE 00 B3 0F 80 B0 14 16
    <- Packet data: 46 B9 68 00 07 80 1E 0D 16
    -> Packet data: 46 B9 6A 00 8C 00 00 00 01 00 00 80 AE 08 AF 09 EE 4F 60 A4 7C 00 7D 00 AA 08 AB 09 EA C3 9E FA EB 9F C3 13 CA 13 CA C3 13 CA 13 CA FB C3 EC 9A ED 9B 50 1E 8E 82 8F 83 C0 07 C0 06 C0 05 C0 04 12 00 85 D0 04 D0 05 D0 06 D0 07 0C BC 00 C9 0D 80 C6 1E BE FF 01 1F 80 B7 75 82 00 22 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF AD 16
    <- Packet data: 46 B9 68 00 07 80 36 25 16
    Writing flash:  75%|█████████████████████████▌        | 384/512 [00:00<00:00, 3814.67 Bytes/s]-> Packet data: 46 B9 6A 00 8C 00 00 00 01 80 00 80 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 77 16
    <- Packet data: 46 B9 68 00 07 80 80 6F 16
    Writing flash: 640 Bytes [00:00, 4207.06 Bytes/s]                                             
    Setting options: -> Packet data: 46 B9 6A 00 0A 8D FD FF FF FF FB 16
    <- Packet data: 46 B9 68 00 0A 8D FD FF FF FF F9 16
    done
    -> Packet data: 46 B9 6A 00 06 82 F2 16
    Disconnected!
    

    SDCC 下的串口

    开启串口, 并将putchar()重定向到串口

    • 对于使用11.0592晶振的STC89C52
      • 使用T1,不加倍时最高波特率只能达到28800, 加倍后是57600
      • 使用T2, T2作为波特率发生器时, 递增频率为晶振频率的2分频, 可以达到115200
    • 对于使用11.0592晶振的STC12C5A60S2, 1T模式波特率达到115200没问题, 如果开了12T模式, 和89C52是一样的

    头文件serial.h

    #ifndef __SERIAL_H__
    #define __SERIAL_H__
    
    #include <mcs51/8051.h>
    
    void serial_init(void);
    
    #endif // __SERIAL_H__
    

    C文件serial.c

    #include "serial.h"
    
    // configure serial for 9600 baud, 8 data bits, 1 stop bit.
    void serial_init(void) {
        TMOD = 0x21;
        SCON = 0x40;
        TH1 = 0xFD;   // TH1 = 256 - 11.0592 * 1000 * 1000 / 12 / 32 / 9600;
        TCON |= 0x40; // start the timer1
        SCON |= 0x02; // tell putchar() the serial is ready to send
    }
    

    如果使用T2, 波特率公式如下:

      波特率 = 11059200 / { 32×[65536-(RCAP2H,RCAP2L)] }
    

    其中的RCAP2H,RCAP2L为自动重装值,由上式得

    RCAP2H, RCAP2L = 65536 - 11059200 / (32×波特率)
    

    这样得波特率为115200时,RCAP2H, RCAP2L = 0xff, 0xfd

    void init_com( void ) { 
        SCON=0x50;   //串口工作方式1,8位UART,波特率可变  
        TH2=0xFF;           
        TL2=0xFD;    //波特率:115200 晶振=11.0592MHz 
        RCAP2H=0xFF;   
        RCAP2L=0xFD; //16位自动再装入值
        TCLK=1;      //波特率发生器工作方式
        RCLK=1;   
        C_T2=0;   
        EXEN2=0;     
        TR2=1 ;      //定时器2开始
    }
    

    SDCC下的时钟中断

    用11.0592MHz晶振的C52产生较精确的1秒定时中断, 定时器初始值由如下计算得到

    • 由晶振11.0592 MHz, 得到定时器时钟为 11.0592 / 12 = 0.9216 MHz,
    • 因此1ms对应 921.6 个时钟周期,
    • 因此50ms对应 46080 个时钟周期,
    • 将其设为一次中断后, 20次中断就对应1s

    代码

    #include <8052.h>
    
    const unsigned char th = (65536 - 46080) / 256;
    const unsigned char tl = (65536 - 46080) % 256;
    volatile unsigned char i = 0;
    
    void main() {
      TMOD= 0x01; //工作方式为16位定时器
      TH0 = th;   //计数寄存器高8位
      TL0 = tl;   //计数寄存器低8位
      EA  = 1;    //允许中断
      ET0 = 0x01; //允许T0中断
      TR0 = 1;    //启动T0
      while(1);
    }
    
    void Timer0IRQ(void) __interrupt (1) // 中断处理函数 T0 -> 中断1
    {
      i++;
      if(i > 20) {
        P0_7 = (P0_7 == 1)? 0 : 1; //触发P0.7 LED闪烁
        i = 1; // 注意这边不能初始化为0, 否则每次会多跑一个中断
      }
      TH0 = th; //计数寄存器高8 位重新载入
      TL0 = tl; //计数寄存器低8 位重新载入
    }
    

    参考

  • 相关阅读:
    HBase 安装设置
    Python中通过函数对象创建全局变量
    Scala 中 构造函数,重载函数的执行顺序
    Hive 安装配置
    976. 三角形的最大周长
    922. 按奇偶排序数组 II
    350. 两个数组的交集 II
    349. 两个数组的交集
    242. 有效的字母异位词
    925. 长按键入
  • 原文地址:https://www.cnblogs.com/milton/p/14994533.html
Copyright © 2011-2022 走看看