执行代码超级短的 STC系列专用 初始化IO口函数 宏定义!!!
本帖最后由 laoxu 于 2023-2-19 21:00 编辑//========================================================================
// 函数: u8 GPIO_Inilize(u8 GPIO, GPIO_InitTypeDef *GPIOx)
// 描述: 初始化IO口.
// 参数: GPIOx: 结构参数,请参考timer.h里的定义.
// 返回: 成功返回 SUCCESS, 错误返回 FAIL.
// 版本: V1.0, 2012-10-22
//========================================================================
u8GPIO_Inilize(u8 GPIO, GPIO_InitTypeDef *GPIOx);
typedef struct
{
u8 Mode; //IO模式, GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP
u8 Pin; //要设置的端口
} GPIO_InitTypeDef;
#################################################################
#################################################################
#################################################################
STC 的 初始化IO口函数, 使用了结构体, 将简单的 对寄存器 PxM1,PxM0 赋值, 搞成一大堆指令。
又是指针,又是判断,程序执行效率极低,我特用宏定义 编写了一个,执行效率极高,功能完全兼容。
程序执行时,仅对寄存器 PxM1,PxM0 赋值, 相当于用 汇编语言直接编写。
当时编写了一个通用型的,能自动识别 STC51、STC16、STC32系列,并给出相对应单片机型的最优化的执行代码。
但后来感觉 H头文件有点复杂有点长,现将其拆分,分别对应于 STC51系列 和 STC251(STC16、STC32)系列 。
现分享给大家 。
网友测试时,可单步运行查看运行结果,也可直接查看检查反汇编程序。
#ifndef __STC_GPIO_H
#define __STC_GPIO_H
/***************************************************************************************
Model : STC_GPIO.H
Description : Head file of defining global variable.
Author : CLR
Create Time : 2023-04-17
Version ID: 2.0
用途 :通用型, 能对宏晶 STC51/STC16/STC32系列MCU,
自动识别, 给出最优化的执行代码!
作者 :许意义
21icID :LAOXU
中颖论坛 : bbs.21ic.com
****************************************************************************************/
//========================================================================
// 定义声明
//========================================================================
// 请注意, 为了便于下面的宏定义, GPIO输入输出模式, 与官方定义不同!!!
#define GPIO_PullUp 0L //上拉准双向口
#define GPIO_OUT_PP 1L //推挽输出
#define GPIO_HighZ 2L //浮空输入
#define GPIO_OUT_OD 3L //开漏输出
/*------------------------------------------------------------------------------------
===========编 程 实 例===========
------Cortex-M051风格1------
1.void GPIO_SET_MODE(Pn, b7,b6,b5,b4,b3,b2,b1,b0); // 设置IO口输入输出模式(n=0-7)
使用方式:
GPIO_SET_MODE(P3, PullUp,HighZ,PullUp,HighZ,OUT_PP,OUT_OD,OUT_PP,OUT_OD);
// 设置P3口的bit.7-bit.0位,依次为PullUp,HighZ,PullUp,HighZ,OUT_PP,OUT_OD,OUT_PP,OUT_OD模式
2.void GPIO_SET_PIN_MODE(Port, Pin_Mode); // 设置IO口其中1位或数位输入输出模式(N=0-7,i=0-7)
例如:
GPIO_SET_PIN_MODE(P3, OUT_OD_Pin6); // 设置P3口的第bit.6位为OUT_OD模式
GPIO_SET_PIN_MODE(P2, PullUp_Pin5 | OUT_PP_Pin2 | HighZ_Pin0); // 设置P2口的第bit.5位为PullUp模式,第bit.2位为OUT_PP模式,第bit.0位为HighZ模式
--------------------------------------------------------------------------------------*/
#define GPIO_SET_MODE(Port, b7,b6,b5,b4,b3,b2,b1,b0) Port##_SET_MODE(b7,b6,b5,b4,b3,b2,b1,b0)
#define GPIO_SET_PIN_MODE(Port, Pin_Mode) Port##_SET_PIN_MODE(Pin_Mode)
/*------------------------------------------------------------------------------------
------Cortex-M051风格2------
3.void Pn_SET_MODE(b7,b6,b5,b4,b3,b2,b1,b0); // 设置Pn IO口输入输出模式(n=0-4)
使用方式:
P3_SET_MODE(PullUp,HighZ,PullUp,HighZ,OUT_PP,OUT_OD,OUT_PP,OUT_OD);
// 设置P3口的bit.7-bit.0位,依次为PullUp,HighZ,PullUp,HighZ,OUT_PP,OUT_OD,OUT_PP,OUT_OD模式
4.void Pn_SET_PIN_MODE(Pin_Mode); // 设置Pn IO口其中1位或数位输入输出模式(N=0-7,i=0-7)
例如:
P3_SET_PIN_MODE(OUT_OD_Pin6); // 设置P3口的第bit.6位为OUT_OD模式
P2_SET_PIN_MODE(PullUp_Pin5 | OUT_PP_Pin2 | HighZ_Pin0); // 设置P2口的第bit.5位为PullUp模式,第bit.2位为OUT_PP模式,第bit.0位为HighZ模式
--------------------------------------------------------------------------------------*/
/*------------------------------------------------------------------------------------
-------51系列风格-------
5.u8 GPIO_Mode(b7,b6,b5,b4,b3,b2,b1,b0);设置IO口输入输出模式
使用方式:
PnMode = GPIO_Mode(b7,b6,b5,b4,b3,b2,b1,b0);设置IO口输入输出模式
P3Mode = GPIO_Mode(PullUp,HighZ,PullUp,HighZ,OUT_PP,OUT_OD,OUT_PP,OUT_OD);
// 设置P3口的bit.7-bit.0位,依次为PullUp,HighZ,PullUp,HighZ,OUT_PP,OUT_OD,OUT_PP,OUT_OD模式
--------------------------------------------------------------------------------------*/
本帖最后由 ayb_ice 于 2023-2-23 11:50 编辑
一个简单的宏被你搞成这么复杂还说别人的复杂,看我的定义
//GPIOI_XXX
//准双向口,标准的51
#define __GPIO_STD(Px, BITy)\
{\
Px##M1 &= ~(BITy);\
Px##M0 &= ~(BITy);\
}
//推挽输出
#define __GPIO_PP(Px, BITy)\
{\
Px##M1 &= ~(BITy);\
Px##M0 |=(BITy);\
}
//高阻输入
#define __GPIO_HZ_INPUT(Px, BITy)\
{\
Px##M1 |= (BITy);\
Px##M0 &= ~(BITy);\
}
//开漏输出
#define __GPIO_OD(Px, BITy)\
{\
Px##M1 |= (BITy);\
Px##M0 |= (BITy);\
}
//输出1
#define __GPIO_SET(Px, BITy)\
{\
Px |=(BITy);\
}
//输出0
#define __GPIO_CLR(Px, BITy)\
{\
Px &=~(BITy);\
}
//反转
#define __GPIO_TGL(Px, BITy)\
{\
Px ^=(BITy);\
}
//BIT
#define BIT(x)(1<<(x))
#define BIT0 BIT(0)
#define BIT1 BIT(1)
#define BIT2 BIT(2)
#define BIT3 BIT(3)
#define BIT4 BIT(4)
#define BIT5 BIT(5)
#define BIT6 BIT(6)
#define BIT7 BIT(7)
#define GPIO_STD(Px_BITx) __GPIO_STD(Px_BITx)
#define GPIO_PP(Px_BITx) __GPIO_PP(Px_BITx)
#define GPIO_HZ_INPUT(Px_BITx)__GPIO_HZ_INPUT(Px_BITx)
#define GPIO_OD(Px_BITx) __GPIO_OD(Px_BITx)
#define GPIO_SET(Px_BITx) __GPIO_SET(Px_BITx)
#define GPIO_CLR(Px_BITx) __GPIO_CLR(Px_BITx)
#define GPIO_TGL(Px_BITx) __GPIO_TGL(Px_BITx)
#define LED1 P2,BIT0
#define LED1_2 P2,(BIT0+BIT1)
#define LED1_ON() GPIO_CLR(LED1)
#define LED1_OFF()GPIO_SET(LED1)
#define LED1_TGL()GPIO_TGL(LED1)
#define LED1_2_ON() GPIO_CLR(LED1_2)
#define LED1_2_OFF()GPIO_SET(LED1_2)
#define LED1_2_TGL()GPIO_TGL(LED1_2)
这是我一直使用的方法,适用不同的MCU,只需要简单的移植,直观,高效,好维护,好移植
使用如下void Test(void)
{
GPIO_PP(LED1);
while (1)
{
LED1_TGL();
Delay(500ms);
LED1_2_TGL();
Delay(500ms);
}
}
ayb_ice 发表于 2023-2-17 09:50
一个简单的宏被你搞成这么复杂还说别人的复杂,看我的定义
我的跟这个基本一样。30年前开始用51,十几年前才用ARM,然后就用这样的宏编程51一样设置、操作ARM的IO,呵呵!我都简化成比如: SET(PA3),CLR(PB2),CPL(PC5)。 coody 发表于 2023-2-17 16:38
我的跟这个基本一样。30年前开始用51,十几年前才用ARM,然后就用这样的宏编程51一样设置、操作ARM的IO, ...
异曲同工 楼上的, 只能对 I/O口, 整体赋值 上拉准双向口//推挽输出/浮空输入/开漏输出 其中一项.
而我这宏定义, 可以对 I/O口的每一位 , 分别 赋值上拉准双向口//推挽输出/浮空输入/开漏输出, 宏定义当然会复杂一些.
这个风格, 完全是 模仿 STC原库, 只是将其 费时费力的结构体指针, 改为 宏定义, 使得编译后的执行代码, 等同于对
寄存器 PxM1,PxM0 直接赋值, 相当于用 汇编语言编写。
原喜欢这种风格的, 可下载参考一下, 不喜欢也没事, 众口难调~~~
不错。
STC也提供IO设置工具及原厂的库函数。
358 本帖最后由 laoxu 于 2023-2-19 21:05 编辑
楼上库文件已更新 !!!
laoxu 发表于 2023-2-18 11:59
楼上的, 只能对 I/O口, 整体赋值 上拉准双向口//推挽输出/浮空输入/开漏输出 其中一项.
而我这宏定义, 可以 ...
不是哦,宏可以单个IO设置,也可以整体赋值。带参数的宏哦。 你们各路大神尽管打架,我在旁边记笔记就行 coody 发表于 2023-2-20 19:04
不是哦,宏可以单个IO设置,也可以整体赋值。带参数的宏哦。
我那可以只对几个需要更改的 I/O口作修改, 你那不行.
例如:
GPIO_SET_PIN_MODE(P2, PullUp_Pin5 | OUT_PP_Pin2 | HighZ_Pin0); // 设置P2口的第bit.5位为PullUp模式,第bit.2位为OUT_PP模式,第bit.0位为HighZ模式 本帖最后由 coody 于 2023-2-25 21:46 编辑
laoxu 发表于 2023-2-24 19:05
我那可以只对几个需要更改的 I/O口作修改, 你那不行.
例如:
我的宏只能设置一种模式,可以单个IO设置,也可以整组IO设置。
只设置一个IO:GPIO_PP(P1, BIT0); //设置P1.0为推挽输出
设置多个IO:GPIO_PP(P1, BIT2+BIT1+BIT0); //设置P1.0 P1.1 P1.2为推挽输出
设置多个IO:GPIO_PP(P2, 0xf0); //设置P2.7 P2.6 P2.5 P2.4为推挽输出
#define LED1 P2,BIT0
只设置一个IO:GPIO_PP(LED1); //设置LED1(P2.0)为推挽输出
只是多一种方法,并不否认你的方法,看各自需要。我喜欢简单的,比较直观,混合设置我担心会混乱。
coody 发表于 2023-2-25 21:40
我的宏只能设置一种模式,可以单个IO设置,也可以整组IO设置。
只设置一个IO:GPIO_PP(P1, BIT0); //设 ...
你的理解不正确.
我这宏定义, 可以对 I/O口的每一位 , 分别 赋值上拉准双向口//推挽输出/浮空输入/开漏输出, 宏定义当然会复杂一些.
是指需要 PxM0,PxM1 同时设置的 情况, 而不是像你现在这样, 对 单一寄存器 赋值.
例如:
GPIO_SET_PIN_MODE(P2, PullUp_Pin5 | OUT_PP_Pin2 | HighZ_Pin0); // 设置P2口的第bit.5位为PullUp模式,第bit.2位为OUT_PP模式,第bit.0位为HighZ模式 而没有设置的位, 维持不变. 本帖最后由 coody 于 2023-3-6 11:01 编辑
laoxu 发表于 2023-3-5 20:03
你的理解不正确.
我这宏定义, 可以对 I/O口的每一位 , 分别 赋值上拉准双向口//推挽输出/浮空输入/开 ...
你可能没细看,我的宏也是一样同时设置 PxM0,PxM1的。
不要怀疑我们的宏做不到,毕竟用来做产品都20多年了,后来移植到ARM,宏操作都一样,移植性非常好。带参数的宏,像函数一样是可以同时操作多个寄存器、变量的。 ayb_ice 发表于 2023-2-17 09:50
一个简单的宏被你搞成这么复杂还说别人的复杂,看我的定义
我是这样写的:
#define Pin0 0x01 //IO引脚 Px.0
#define Pin1 0x02 //IO引脚 Px.1
#define Pin2 0x04 //IO引脚 Px.2
#define Pin3 0x08 //IO引脚 Px.3
#define Pin4 0x10 //IO引脚 Px.4
#define Pin5 0x20 //IO引脚 Px.5
#define Pin6 0x40 //IO引脚 Px.6
#define Pin7 0x80 //IO引脚 Px.7
#define PinAll 0xFF //IO所有引脚
#define P0n_standard(bitn) P0M1 &= ~(bitn), P0M0 &= ~(bitn) //00 标准
#define P0n_push_pull(bitn) P0M1 &= ~(bitn), P0M0 |=(bitn) //01 推挽
#define P0n_pure_input(bitn) P0M1 |=(bitn), P0M0 &= ~(bitn) //10 输入
#define P0n_open_drain(bitn) P0M1 |=(bitn), P0M0 |=(bitn) //11 开漏
#define P1n_standard(bitn) P1M1 &= ~(bitn), P1M0 &= ~(bitn)
#define P1n_push_pull(bitn) P1M1 &= ~(bitn), P1M0 |=(bitn)
#define P1n_pure_input(bitn) P1M1 |=(bitn), P1M0 &= ~(bitn)
#define P1n_open_drain(bitn) P1M1 |=(bitn), P1M0 |=(bitn)
页:
[1]