有什么网站可以在线做试题,wordpress添加一个tag页面,网站建设怎么分录,深圳百度关键词排名文章目录 一、C51 单片机模板创建1. 新建工程及选型2. 创建主程序文件3. 创建主程序的头文件4. 编译配置5. 其他 二、C51 的编码规范 在查阅了很多关于 C51 单片机的程序后#xff0c;个人感觉目前网上有关 C51 单片机程序的质量参差不齐#xff0c;很多程序的代码风格及其糟… 文章目录 一、C51 单片机模板创建1. 新建工程及选型2. 创建主程序文件3. 创建主程序的头文件4. 编译配置5. 其他 二、C51 的编码规范 在查阅了很多关于 C51 单片机的程序后个人感觉目前网上有关 C51 单片机程序的质量参差不齐很多程序的代码风格及其糟糕可读性也很差
1。除了新手如此很多写了多年程序的程序员老手也如此也包括笔者还处于新手期的时候在在乎程序是否可以正常运行而忽略了程序的可读性、可维护性、可复用性以及可扩展性。 由于工作时笔者所在的公司在编码风格和规范上有及其严格的规定所以决定总结一下我对我在编写 C51 单片机程序时的编码规范。本文以猿学社上官一号开发板核心为 STC89C52RC为基础而编写编码风格为 KR笔者之前干的是 Linux 内核驱动开发工作用的就是这个风格变量和函数使用下划线命名法。 本文前置要求
已安装了 C51 的开发环境 Keil uVision5未安装的建议参考博客《Keil MDK 与 Keil C51 共存的方法》该文同时安装了 STM32 等主流 32 位单片机的开发环境并解决了两个软件的共存问题。下载 C51 单片机的烧录工具软件下载地址工具软件 STC-ISP
一、C51 单片机模板创建
模板的好处在于新建项目时可以省去选型、添加必要文件等步骤只要是同一个芯片的项目复制模板后就可以直接开始编码工作。
模板已同步到 GitHub 和 Gitee欢迎指正和查阅。
GitHub 链接
Gitee 链接
1. 新建工程及选型
运行 Keil uVision5在最上面的菜单找到 Project 并点击弹出下拉菜单后选择第一个 New μVision Project 。 随后的弹窗中为存放项目的文件夹我个人的习惯是将所有的代码都放在一个名为 Code 的文件夹中在里面再具体分类是什么类型的代码如果是 C51 的代码会专门新建一个文件夹来存放这里为了演示直接在 D 盘新建了 C51 的文件夹。然后在文件夹中再新建一个文件夹名为 template也就是模板的意思双击进入文件夹在下方的文件名再次输入 template点击 保存。 接着是选型弹窗由于我的 Keil 包含了 MDK 版本所以在选型时要先切换到 Legacy Device Database意思是旧设备数据库然后按下图操作即可。这里解释一下为什么选择 89C52而不是 89C51首先这两者的架构是一样的都是 Intel 8051 架构而上官一号采用的芯片是 STC89C52RC故选 89C52其次C52 比 C51 多个更多的外设例如C51 拥有 4KB 的 ROM 作为程序存储空间而 C52 是更大的 8KBC51 只有两个 16 位定时器/计数器T0 和 T1而 C52 多一个额外的 16 位定时器/计数器T2等等。当然了选择 89C51 也可能正常编译程序并烧录进单片机运行只是通常会选择与芯片相同的型号最佳。 不过这里也有人注意到了现在的 C51 单片机基本都是 STC 生产的深圳宏晶科技为什么可以用 AT89C52 来代替 STC89C52 呢其实这个无所谓选哪个只要是 89C52 都可以反正架构是一样的就行。
选好芯片型号后在随后的弹窗中选择 是不然程序不能正常编译这是 C51 的启动文件。 2. 创建主程序文件
在左边的项目侧边栏中逐级点开 Target 1 - Source Group 1然后鼠标右键点击 Source Group 1在弹出的菜单中选择 Add New Item to Group Source Group 1。 在随后的弹窗中按下图所示操作目的是创建 main.c 作为主程序文件。 创建成功后输入下面的代码作为基础模板。
/********************************************************************* File: * Description: * Version: * Date: * Author: * ---------- Revision History ----------* version date author desc* ********************************************************************/#include main.h/* User Code Includes *//* User Code Define *//* User Code Global Variables *//* User Code Function prototypes *//* ------------------------------ Division Line ------------------------------ *//*** brief Initialize all configured.*/
void setup(void)
{/* put your setup code here, to run once: */}/*** brief The application entry point.*/
void main(void)
{/* Private variables *//* Initialize */setup();/* Infinite loop */while (TRUE){/* put your main code here, to run repeatedly: */}
}
简单说明以下这个代码框架的含义熟悉 Arduino 的同学应该一眼就看出我是抄了 Arduino IDE 的默认程序框架setup() 是用于做初始化的函数这个函数只运行一次后面主要用于循环执行的程序则放在 mian() 函数中的 while(TRUE) 里。其他的注释基本是参考 CubeMX 生成的 Keil 代码具体解释如下
/* User Code Includes */在这个注释下可以添加其他头文件。/* User Code Define */在这个注释下添加程序需要的宏定义。/* User Code Global Variables */在这个注释下添加全局变量。/* User Code Function prototypes */在这个注释下添加函数原型。/* Private variables */main() 函数中还有 /* Private variables */由于 C51 采用的是 C90 的编码标准所有局部变量都只能写在函数最前端故设此注释可在此注释下添加 main() 函数的局部变量。
最前面的一大块注释是文件的描述这个后面再做具体的解释当前效果如下图 3. 创建主程序的头文件
相信大家也都注意到了在主文件中的 main.h 头文件目前是不存在的以及 while 循环的条件是 TRUE这个也是目前不存在的变量或宏定义所以接下来就要创建对应的头文件。
与创建 .c 文件差不多创建头文件只需要选择 Header File(.h) 即可。 然后在 main.h 文件中输入以下代码
/********************************************************************* File: bit.h* Description: 89C51/89C52 main header files.* Version: 1.0* Date: 2024-04-25* Author: zhengxinyu13gmail.com* ---------- Revision History ----------* version date author desc* ********************************************************************/#ifndef __MAIN_H__
#define __MAIN_H__#include STC89C5xRC-rdp.h#define HIGH 1
#define LOW 0
#define TRUE 1
#define FALSE 0
#define TURN_ON 1
#define TURN_OFF 0#define SET(pin) (pin) 1
#define RESET(pin) (pin) 0typedef unsigned char uint8_t;
typedef signed char int8_t;
typedef unsigned int uint16_t;
typedef signed int int16_t;
typedef unsigned long uint32_t;
typedef signed long int32_t;#include delay.h#endif // __MAIN_H__
整个头文件用 #ifndef #define #endif 的结构可以防止重复定义。__MAIN_H__ 这个宏的命名方式也是行业约定俗成的命名方法两个下划线开头然后就是头文件名字的大写中间的点用下划线代替再两个下划线结尾。#endif 最后都会习惯用双斜杠注释最开始定义的宏表示这个 #endif 是从哪个 #ifndef 开始的。
中间是一些常用的宏定义typedef 关键字后面重定义了一些数据类型这些类型别名使得代码更加可读并且有助于提升代码的可移植性。这些数据类型取自 stdint.h 这个头文件但是因为 C51 单片机使用的还是 C90 的标准该头文件为 C99 标准时引入的头文件因此没办法在这插入所以才使用了typedef 关键字进行重定义。
regx51.h 头文件是 Keil 安装时就已经引入不需要用户自定义但是这个头文件并不完整例如像特殊寄存器 AUXR、WDT_CONTR 等都未定义也没有定义 P4 引脚所以 STC89C5xRC-rdp.h 头文件对此进行了补充该文件非笔者编写而是由烧录软件 STC-ISP 自动生成。 具体代码如下
/*--------------------------------------------------------------------------
STC89C5xRC-rdp.hSupplemental header files for Low Voltage Flash Atmel AT89C52 and AT89LV52.
--------------------------------------------------------------------------*/#ifndef __STC89C5xRC_RDP_H__
#define __STC89C5xRC_RDP_H__///包含本头文件后,不用另外再包含REG51.Hsfr P0 0x80;sbit P00 P0^0;sbit P01 P0^1;sbit P02 P0^2;sbit P03 P0^3;sbit P04 P0^4;sbit P05 P0^5;sbit P06 P0^6;sbit P07 P0^7;sfr SP 0x81;
sfr DPL 0x82;
sfr DPH 0x83;
sfr PCON 0x87;sfr TCON 0x88;sbit TF1 TCON^7;sbit TR1 TCON^6;sbit TF0 TCON^5;sbit TR0 TCON^4;sbit IE1 TCON^3;sbit IT1 TCON^2;sbit IE0 TCON^1;sbit IT0 TCON^0;sfr TMOD 0x89;
sfr TL0 0x8A;
sfr TL1 0x8B;
sfr TH0 0x8C;
sfr TH1 0x8D;
sfr AUXR 0x8E;sfr P1 0x90;sbit P10 P1^0;sbit P11 P1^1;sbit P12 P1^2;sbit P13 P1^3;sbit P14 P1^4;sbit P15 P1^5;sbit P16 P1^6;sbit P17 P1^7;sbit T2EX P1^1;sbit T2 P1^0;sfr SCON 0x98;sbit SM0 SCON^7;sbit SM1 SCON^6;sbit SM2 SCON^5;sbit REN SCON^4;sbit TB8 SCON^3;sbit RB8 SCON^2;sbit TI SCON^1;sbit RI SCON^0;sfr SBUF 0x99;sfr P2 0xA0;sbit P20 P2^0;sbit P21 P2^1;sbit P22 P2^2;sbit P23 P2^3;sbit P24 P2^4;sbit P25 P2^5;sbit P26 P2^6;sbit P27 P2^7;sfr AUXR1 0xA2;sfr IE 0xA8;sbit EA IE^7;sbit EC IE^6;sbit ET2 IE^5;sbit ES IE^4;sbit ET1 IE^3;sbit EX1 IE^2;sbit ET0 IE^1;sbit EX0 IE^0;sfr SADDR 0xA9;sfr P3 0xB0;sbit P30 P3^0;sbit P31 P3^1;sbit P32 P3^2;sbit P33 P3^3;sbit P34 P3^4;sbit P35 P3^5;sbit P36 P3^6;sbit P37 P3^7;sbit RD P3^7;sbit WR P3^6;sbit T1 P3^5;sbit T0 P3^4;sbit INT1 P3^3;sbit INT0 P3^2;sbit TXD P3^1;sbit RXD P3^0;sfr IPH 0xB7;
sfr IP 0xB8;sbit PT2 IP^5;sbit PS IP^4;sbit PT1 IP^3;sbit PX1 IP^2;sbit PT0 IP^1;sbit PX0 IP^0;sfr SADEN 0xB9;sfr XICON 0xC0;sbit PX3 XICON^7;sbit EX3 XICON^6;sbit IE3 XICON^5;sbit IT3 XICON^4;sbit PX2 XICON^3;sbit EX2 XICON^2;sbit IE2 XICON^1;sbit IT2 XICON^0;sfr T2CON 0xC8;sbit TF2 T2CON^7;sbit EXF2 T2CON^6;sbit RCLK T2CON^5;sbit TCLK T2CON^4;sbit EXEN2 T2CON^3;sbit TR2 T2CON^2;sbit C_T2 T2CON^1;sbit CP_RL2 T2CON^0;sfr T2MOD 0xC9;
sfr RCAP2L 0xCA;
sfr RCAP2H 0xCB;
sfr TL2 0xCC;
sfr TH2 0xCD;sfr PSW 0xD0;sbit CY PSW^7;sbit AC PSW^6;sbit F0 PSW^5;sbit RS1 PSW^4;sbit RS0 PSW^3;sbit OV PSW^2;sbit F1 PSW^1;sbit P PSW^0;sfr ACC 0xE0;sfr WDT_CONTR 0xE1;
sfr ISP_DATA 0xE2;
sfr ISP_ADDRH 0xE3;
sfr ISP_ADDRL 0xE4;
sfr ISP_CMD 0xE5;
sfr ISP_TRIG 0xE6;
sfr ISP_CONTR 0xE7;sfr P4 0xE8;sbit P40 P4^0;sbit P41 P4^1;sbit P42 P4^2;sbit P43 P4^3;sbit P44 P4^4;sbit P45 P4^5;sbit P46 P4^6;sbit P47 P4^7;sfr B 0xF0;/#endif
代码也提示了不需要再添加regx51.h 头文件了。
最后还有一个 delay.h 头文件需要同时在工程中新建一个 delay.h 和一个 delay.c内容如下
/********************************************************************* File: delay.h* Description: Time delay function based on 11.0592MHz crystal* oscillator.* crystal oscillator.* Version: 1.0* Date: 2023-07-17* Author: zhengxinyu13gmail.com* ---------- Revision History ----------* version date author desc* ********************************************************************/#ifndef __DELAY_H__
#define __DELAY_H__#include main.h
#include intrins.hvoid delay_ms(uint16_t xms);
void delay_1s(void);#endif // __DELAY_H__
/********************************************************************* File: delay.h* Description: Delay function library based on 11.0592MHz* crystal oscillator.* Version: 1.0* Date: 2023-07-17* Author: zhengxinyu13gmail.com* ---------- Revision History ----------* version date author desc* ********************************************************************/#include delay.h/*** brief Delay function in milliseconds.* param Enter the delay time in milliseconds.*/
void delay_ms(uint16_t xms)
{uint16_t i,j;for (i 0; i xms; i)for (j 0; j 112; j);
}/*** brief Delay by one second.*/
void delay_1s(void)
{uint8_t i, j, k;_nop_();i 8;j 1;k 243;do {do {while (--k);} while (--j);} while (--i);
}这里特殊说明一下这个延时函数的文件不是必要的只是延时函数在 C51 的开发过程中太常见了所以加上去方便后面的开发。 [!NOTE] 实际项目的单片机开发不会用在这种软件延时太占用 CPU 了通常是用定时中断计时考虑到 C51 的资源太匮乏在学习开发阶段可以使用软件延时。 4. 编译配置
最后需要配置编译否则编译后也不会生成 .hex 文件在菜单栏中找打类似魔术棒一样的图标并点击。 这里建议把晶振频率设置成实际开发的频率一般都是 11.0592MHz。 然后点击选项卡 Output把 Create HEX File 勾上Name of Executable 是编译后的 .hex 文件的文件名我习惯使用 build。最后点击 OK 完成配置。 点击编译试一下如果在下面的 Bulid Output 中出现 creating hex file from .\Objects\build... 的字样就表示编译通过并生成了 .hex 文件。有两个警告是因为 delay.c 中写了两个延时函数没有调用导致知道原因可以忽略。 5. 其他
考虑到很多英文水平不好的同学写英文注释比较难受可以使用中文注释建议修改成 UTF-8。先在菜单栏找到小扳手的图标并打开在 Encoding 中选择 Encode in UTF-8 without signature不建议选择 GB2312 或者 BIG5因为有些字符无法显示。 如果有同学对我的 Keil 主题比较感兴趣的话我可以单独出一篇博客细说一下。
二、C51 的编码规范
关于编码规范我基本都有比较统一的标准可以直接参考我的博客《关于我个人的编码规范C/C》这里只补充一点这规范中我提到要将 tab 键设置成 4 个空格统一用 tab 键缩进这里教大家怎么把 Keil 的 tab 设置成 4 个空格。
按图设置即可。 个人感觉郭天祥老师有一定责任当年他培养出新世纪以来第一批嵌入式工程师他的十天学会 C51 的课程以及那本新概念的书功不可没但是其课程和书的代码风格都很乱这也可能是后来很多单片机工程师代码风格很差的一个原因。 ↩︎