前言
下学期学校即将教授STC15单片机,寒假闲暇之余,花了20大洋买了块STC32来看看,听说是STC公司的32位单片机有点好奇,将与之前接触的STM32进行比较,顺便复习一下8051单片机的结构和寄存器,也顺便对下学期的单片机课程预习。
寄存器配置及讲解
于是话不多说,我们直击话题GPIO口的使用,首先先关注几个寄存器的使用
首先手册寄存器中的x为端口,x=0~7
通过查看手册发现,虽说STC32为32位单片机,但是寄存器还是多为8位,因此还是换汤不换药
下列寄存器B7~B0分别对应端口Px中Pin7到Pin0的配置
这个我们一看在89C52中就知道是老朋友了,输出直接赋值就行,输入直接读取便行,这就是8051单片机的便利之处,不必像STM32初始无法直接位带操作
该寄存使能输入模式,所以在输入模式下必需为1才可使能输入,但是查看手册发现它的缺省值(复位值)为1所以不用太管它,但在作为ADC输入口是就要设置为0了。
随后这两个寄存顾名思义,配置上下拉电阻,配置上下拉电阻有一定驱动电流的能力,并且有置输入模式默认电平的作用。
随后是重头戏,PxM0和PxM1的配置影响着GPIO模式配置
准双向口和我们是老朋友了,我们在89C52芯片中就都是准双向口
这边用到了弱上拉,因此配置完成电平默认高电平,但是此时驱动电流LED灯亮度较低,但是对其引脚电平赋完值便能驱动正常的电流,这边便是用到了强上拉
随后推挽输出运用到强下拉,与STM32推挽输出的强下拉弱上拉不同,因此配置完成默认高电平
且因为强上拉,电流也较大,LED灯也是正常的亮度
开漏模式中要正确读取外部状态时要外接上拉电阻和电源,因此使用开漏输出要注意寄存器PxPU的配置。
在高阻输入模式,在我看来和STM32的浮空输入是类似的,但是经过尝试此时就算接上拉电阻和下来电阻也对其电平无影响,电平是未知的来回跳动的。
然后对于GPIO寄存器的配置要注意复位值,不要理所当然的认为都是0
代码
以下是自己对GPIO配置写的一个函数,有点参考STM32库函数的配置函数
(1)源文件
#include "GPIO.h"
//Mode=GPIO_Mode_InOut,Pull为 上拉输入模式
//Mode=GPIO_Mode_Out_OD是应设置Pull为Pull_Up,此时设置为开漏输出
void GPIO_Init(uint8_t Port,uint8_t Pin,GPIO_Mode Mode,GPIO_Pull Pull)
{
//Parameters: Port:0~7 Pin:0~7 Mode[1:0]共两位 Pull[1:0]共两位
uint8_t MSB=(0x2&Mode)>>1;//取形参Mode高位为PxM1配置
uint8_t LSB=(0x1&Mode);//取形参Mode低位为PxM0配置
uint8_t MSB_1=(0x2&Pull)>>1;//取形参Pull高位为PxPU配置
uint8_t LSB_1=(0x1&Pull);//取形参Pull低位为PxPU配置
switch(Port)
{
case 0:P0M1&=~(0x01<<Pin),P0M0&=~(0x01<<Pin),//将该位的模式配置寄存器的设置都清0
P0PU&=~(0x01<<Pin),P0PD&=~(0x01<<Pin), //将该位的上下拉电阻使能寄存器都清0
P0PU|=(MSB_1<<Pin),P0PD|=(LSB_1<<Pin), //配置该位模式配置寄存器
P0M1|=(MSB<<Pin),P0M0|=(LSB<<Pin);break; //配置该位上下拉电阻使能寄存器
case 1:P1M1&=~(0x01<<Pin),P1M0&=~(0x01<<Pin),
P1PU&=~(0x01<<Pin),P1PD&=~(0x01<<Pin),
P1PU|=(MSB_1<<Pin),P1PD|=(LSB_1<<Pin),
P1M1|=(MSB<<Pin),P1M0|=(LSB<<Pin);break;
case 2:P2M1&=~(0x01<<Pin),P2M0&=~(0x01<<Pin),
P2PU&=~(0x01<<Pin),P2PD&=~(0x01<<Pin),
P2PU|=(MSB_1<<Pin),P2PD|=(LSB_1<<Pin),
P2M1|=(MSB<<Pin),P2M0|=(LSB<<Pin);break;
case 3:P3M1&=~(0x01<<Pin),P3M0&=~(0x01<<Pin),
P3PU&=~(0x01<<Pin),P3PD&=~(0x01<<Pin),
P3PU|=(MSB_1<<Pin),P3PD|=(LSB_1<<Pin),
P3M1|=(MSB<<Pin),P3M0|=(LSB<<Pin);break;
case 4:P4M1&=~(0x01<<Pin),P4M0&=~(0x01<<Pin),
P4PU&=~(0x01<<Pin),P4PD&=~(0x01<<Pin),
P4PU|=(MSB_1<<Pin),P4PD|=(LSB_1<<Pin),
P4M1|=(MSB<<Pin),P4M0|=(LSB<<Pin);break;
case 5:P5M1&=~(0x01<<Pin),P5M0&=~(0x01<<Pin),
P5PU&=~(0x01<<Pin),P5PD&=~(0x01<<Pin),
P5PU|=(MSB_1<<Pin),P5PD|=(LSB_1<<Pin),
P5M1|=(MSB<<Pin),P5M0|=(LSB<<Pin);break;
case 6:P6M1&=~(0x01<<Pin),P6M0&=~(0x01<<Pin),
P6PU&=~(0x01<<Pin),P6PD&=~(0x01<<Pin),
P6PU|=(MSB_1<<Pin),P6PD|=(LSB_1<<Pin),
P6M1|=(MSB<<Pin),P6M0|=(LSB<<Pin);break;
case 7:P7M1&=~(0x01<<Pin),P7M0&=~(0x01<<Pin),
P7PU&=~(0x01<<Pin),P7PD&=~(0x01<<Pin),
P7PU|=(MSB_1<<Pin),P7PD|=(LSB_1<<Pin),
P7M1|=(MSB<<Pin),P7M0|=(LSB<<Pin);break;
}
}
(2)头文件
#ifndef __GPIO_H__
#define __GPIO_H__
#include <STC32G.H>
typedef enum
{
GPIO_Mode_InOut=0x0,
GPIO_Mode_Out_PP=0x1,
GPIO_Mode_Out_OD=0x3,
GPIO_Mode_InFloating=0x2
}GPIO_Mode;
typedef enum
{
GPIO_NoPull=0x0,
GPIO_Pull_Up=0x2,
GPIO_Pull_Down=0x1
}GPIO_Pull;
void GPIO_Init(uint8_t Port,uint8_t Pin,GPIO_Mode Mode,GPIO_Pull Pull);
#endif
(3)在<STC32G.H>文件这边运用到了枚举定义uint,毕竟习惯了STM32的命名
#ifndef __STC32G_H__
#define __STC32G_H__
typedef unsigned char uint8_t;
typedef unsigned int uint16_t;
typedef unsigned long uint32_t;
typedef char int8_t;
typedef int int16_t;
typedef long int32_t;
总结
总体来说比89C52多出了很多模式功能可以运用到更多的场景,对比STM32还是很多不同的,还是要多查阅手册,但这也有个比较疑惑的地方就是下拉输入发现没有实现不知道什么原因,还要继续去探索哈
如果有错误,还望大家指证哈^o^