STC89C52操作GPIO口LED灯
- 1 芯片介绍
- 1.1 芯片类型
- 1.2 芯片系列说明
- 2 GPIO引脚寄存器说明
- 3 GPIO操作
- 3.1 GPIO输入
- 3.2 GPIO输出
- 3.3 GPIO流水灯
- 3.4 Protues仿真
- 4 总结
1 芯片介绍
1.1 芯片类型
芯片采用宏晶科技品牌下的STC89C52RC单片机
选择STC89C52RC系列STC89C58RD+系列单片机的理由:
★加密性强
★超强抗干扰:
1、高抗静电(ESD保护)
2、轻松过 2KV/4KV 快速脉冲干扰(EFT 测试)
3、宽电压,不怕电源抖动
4、宽温度范围,-40℃℃~85℃℃
★三大降低单片机时钟对外部电磁辐射的措施:–出口欧美的有力保证
1、禁止ALE 输出;
2如选6时钟/机器周期,外部时钟频率可降一半;3、单片机时钟振荡器增益可设为 1/2gain。
★超低功耗:
1 、掉电模式:典型功耗<0.1 μA2、正常工作模式:典型功耗4MA - 7MA3、掉电模式可由外部中断唤醒,适用于电池供电系统,如水表、气表、便携设备等。
★在系统可编程,无需编程器,无需仿真器
★可送STC-ISP下载编程器,1万片/人/天
★可供应内部集成MAX810专用复位电路的单片机只有D 版本才有内部集成专用复位电路,原复位电路可以保留,也可以不用,不用时RESET脚接1K电阻到地
1.2 芯片系列说明
STC89C52RC芯片最高工作时钟频率为80M,flash内存有8K大小,RAM空间512字节,足以满足日常学习课单一功能的实现应用。
STC89C52RC/RD+ 系列单片机是宏晶科技推出的新一代超强抗干扰/高速/低功耗的单片机,指令代码完全兼容传统8051单片机,12时钟/机器周期和6时钟/机器周期可任意选择,最新的D版本内部集成 MAX810 专用复位电路。
特点:
1.增强型6时钟/机器周期,12时钟/机器周期 8051 CPU
2.工作电压:5.5V-3.4V(5V单片机) / 3.8V - 2.0V(3V 单片机)3.工作频率范围:0-40 MHz,相当于普通8051的 0~80MHz.实际工作频率可达 48MHz.4.用户应用程序空间4K/8K/13K/16K/20K/32K/64K 字节
5.片上集成 1280 字节 /512字节 RAM
6.通用1/0口(32/36个),复位后为: P1/P2/P3/P4是准双向口上拉(普通8051传统 1/0 口)P0 口是开漏输出,作为总线扩展用时,不用加上拉电阻,作为1/0口用时,需加上拉电阻。7.ISP(在系统可编程)/IAP(在应用可编程),无需专用编程器/仿真器可通过串口(P3.0/P3.1)直接下载用户程序,8K程序3秒即可完成一片
8.EEPROM 功能
9.看门狗
10.内部集成MAX810 专用复位电路(D 版本才有),外部晶体20M 以下时,可省外部复位电路11.共3个16 位定时器/计数器,其中定时器0还可以当成2个8位定时器使用12.外部中断4路,下降沿中断或低电平触发中断,Power Down模式可由外部中断低电平触发中断方式唤醒13.通用异步串行口(UART),还可用定时器软件实现多个 UART
14.工作温度范围:0-75℃℃/-40-+85℃℃
15.封装: LOFP-44,PDIP-40,PLCC-44,POFP-44,如选择STC89 系列,请优先选择LOFP-44 封装
2 GPIO引脚寄存器说明
手册说明:通用1/0口(32/36个),复位后为: P1/P2/P3/P4是准双向口上拉(普通8051传统1/0口)P0 口是开漏输出,作为总线扩展用时,不用加上拉电阻,作为1/0口用时,需加上拉电阻。
查看芯片的寄存器寻址框图,GPIO寄存器位置在80h、90h、A0h、B0h、E8h.
寄存器分别为P0/P1/P2/P3/P4,没有其他特殊的类似于高级芯片的方向控制上下拉控制寄存器等,操作简单易用。
3 GPIO操作
结合第一章节将工程重新整理
(1)切换使用keil5版本,根据第节说明的,将STC的的芯片包重新安装到KEIL5安装目录下即可,并按照同样的方式创建工程。
(2)工程架构整理,为了使工程看起来具有较高的可读性,我将led控制的gpio程序独立到c51_gpio.c,并建立c51_gpio.h,用于声明c51_gpio.c创建的函数和变量,创建includes.h用于引用所有的头文件和部分系统函数及变量。
C51_gpio.c
#include "includes.h"
void sys_led(void)
{
}
/********************************************************
函数名称:sys_led_test
函数功能:IO口高低电平控制
入口参数:
出口参数:
修 改:
内 容:现在实现D0/D2/D4/D6指示灯亮起,
D1/D3/D5/D7指示灯灭掉,并演示
********************************************************/
void sys_led_test(void)
{
P1 = 0xFF; //P1口全部为高电平,对应的LED灯全灭掉,ff换算成二进制是 1111 1111
P1 = 0x00; //P1口全部为低电平,对应的LED灯全亮起,ff换算成二进制是 0000 0000
P1 = 0x55; //D0/D2/D4/D6指示灯亮起
//D1/D3/D5/D7指示灯灭掉,AA换算成二进制是 1010 1010
}
C51_gpio.h
#ifndef __C51_GPIO_H__
#define __C51_GPIO_H__
extern void sys_led(void);
extern void sys_led_test(void);
#endif
includes.h
#ifndef __INCLUDES_H__
#define __INCLUDES_H__
//#include<reg52.h>
//包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义
#include "STC89C5xRC_RDP.h"
//应用层头文件
#include "c51_gpio.h"
#endif
(3)根据串口助手提示更新芯片头文件放置工程的include文件夹中
我创建的名称为STC89C5xRC_RDP.h,并在includes.h中引用,屏蔽//#include<reg52.h>
#ifndef __STC89C5xRC_RDP_H__
#define __STC89C5xRC_RDP_H__
/
//包含本头文件后,不用另外再包含"REG51.H"
sfr 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
至此工程整理完毕,接下来进行程序验证。
3.1 GPIO输入
GPIO输入检测即是对PX引脚的检测直接获取寄存器P的值即可。
先控制4个IO口输出为高低不同的电平,再用另外4个IO口获取前面4个端口的电平,并测试获取之后的电平状态是否是先前输出的电平状态。
程序代码如下:
void sys_led_test(void)
{
unsigned char tmp = 0;//中间变量用于获取io口状态
//控制4个引脚输出
P10 = 1;
P11 = 0;
P12 = 0;
P13 = 1;
//用另外四个IO口获取状态并测试(指示灯显示)
tmp = P10;
P14 = tmp;
tmp = P11;
P15 = tmp;
tmp = P12;
P16 = tmp;
tmp = P13;
P17 = tmp;
}
根据测试结果可知,获取IO口状态,直接读出对应寄存器位即可
3.2 GPIO输出
同理,控制GPIO口状态,直接写入寄存器即可,根据STC89C5xRC_RDP.h可知:
Pxy:x指的是端口名称,y指的是这个名称下的端口序号。
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;
3.3 GPIO流水灯
流水灯控制肯定要用到延时函数,首先定义一个简单的delay函数,并在includes.h中声明
/*------------------------------------------------
延时子程序
------------------------------------------------*/
void delay(unsigned int cnt)
{
while(--cnt);
}
然后再c51_gpio.c中定义一个跑马灯程序,并在主程序的while(1)中使用,在c51_gpio.h中进行声明。
Led流水灯函数如下,其实在以下两句之间有一小段时间P1.0引脚出来的是低电平,在仿真时可以看出来。
P1<<=1; //左移一位 该语句等效于 P1=P1<<1
P1|=0x01; //最后一位补1,该语句等效于 P1=P1|0x01 符号"|“表示"或”
/********************************************************
函数名称:sys_led_test
函数功能:led流水灯
入口参数:
出口参数:
修 改:
内 容:
********************************************************/
void sys_led_test1(void)
{
delay(30000);//延时程序
P1<<=1; //左移一位 该语句等效于 P1=P1<<1
P1|=0x01; //最后一位补1,该语句等效于 P1=P1|0x01 符号"|"表示"或"
if(P1==0x7f) //检测是否移到最左端?"=="表示检测符号2端的值是否相等
{
delay(30000);
P1=0xfe; //重新赋值
}
}
烧录板子验证,流水灯成功。
3.4 Protues仿真
Protues仿真可以摆脱硬件的瓶颈,但是需要对器件特性有一定的了解,此处制作简单演示,后续完结后使用protues演示几个项目
4 总结
做一件事很容易,如何把这件事做好,做到自己满意的程度,需要花费心思和精力,实现功能很容易,实现具有高可靠性的功能需要再接再厉。
欢迎大家交流。