目录
一、前言
二、前置知识
1.带参宏定义
2.三目运算符
3.需要用到的寄存器
①BSRR寄存器
②BRR寄存器
③IDR寄存器
三、有以上基础或者想直接用的直接看这里
1.使用宏定义来控制IO口
四、代码解释
1.LED(x)
2.LED_RUN
五、结语
一、前言
突然想用宏定义来控制IO口,但是发现网上并没有比较满意的解决方案,所以自己就写了一个,现在分享出来给大家用。其中用到了带参宏定义和三目运算符,还有一些寄存器的知识,有基础的可以直接从《前置知识》后面看,没基础的我会在《前置知识》简单介绍一下,具体的可以自己去搜索学习一下,想直接用不想知道那么多的同学直接跳到《有以上基础或者想直接用的直接看这里》。
二、前置知识
1.带参宏定义
带参宏定义的格式一般如下,注意:严格上说并不是真正的参数,只是替换而已。
#define 宏名(参数1,参数2,...) 字符串
示例程序,如:
#define add(a,b) a+b
void add(void)
{
int mnb;
mnb = add(1,2);
}
因为这个宏定义会将结果返回,所以这个时候mnb就会等于3。
2.三目运算符
三目运算符为?:
其中表达式为(真/假)?(真的话执行这段):(假的话执行这段)
我习惯在三目运算符上面加括号,这样可以避免运算优先级带来的问题。
不加括号的话就是:
真/假?真的话执行这段:假的话执行这段
示例程序,如:
int AAA(int mnb)
{
int a = (mnb>5)?(mnb-1):(mnb+1);
return a;
}
这段代码的意思就是说先将AAA的形参mnb用来判断是否大于5,当大于5的时候返回mnb-1赋值给a,否则返回mnb+1赋值给a,最后函数返回a的值。
3.需要用到的寄存器
①BSRR寄存器
全称为“端口位设置/清除寄存器”
有高16位和低16位,这里我只用到了低16位,所以只介绍低16位。
BSRR中的低16位中某一位或者多位置1了,就会将对应的引脚拉高,而置0就是保持当前引脚状态不变。
如:
GPIOA->BSRR = 1 << 0; //将PA0拉高
GPIOA->BSRR = GPIO_Pin_0; //将PA0拉高
上面两个段代码是一样的效果,就看你喜欢用哪个了。
②BRR寄存器
全称为“端口位清除寄存器”
这个只有16位,且跟BSRR是反着来的,也就是说置1会将对应引脚拉低,而置0也是保持当前引脚状态不变。
如:
GPIOA->BRR = 1 << 0; //将PA0拉低
GPIOA->BRR = GPIO_Pin_0; //将PA0拉低
上面两个段代码也是一样的效果。
③IDR寄存器
IDR是只读寄存器,全称为“端口输入数据寄存器”,是用来读取引脚状态的寄存器。
如:
int a = GPIOA->IDR & GPIO_Pin_0;
上面的代码就是检测PA0引脚的状态,并且将返回值赋值给a。
注意:它是按位返回,如pin0为高它返回0x01,pin3为高它返回0x08。
三、有以上基础或者想直接用的直接看这里
1.使用宏定义来控制IO口
前置知识都会的话,我们就可以进入正题了。
我这里以我们最熟悉的控制LED来举例,并且写出两种控制模式,其他的你们就可以举一反三了。
GPIO口的初始化之类的代码我这里就不给出了,有需要的可以自己搜一下。直接给出代码:
//硬件上以GPIOA中的Pin0为LED,并以高电平为亮,以低电平为灭。
//控制IO高低电平
#define LED(x) ((x==1) ? (GPIOA->BSRR=GPIO_Pin_0) : (GPIOA->BRR=GPIO_Pin_0))
//控制IO口翻转电平
#define LED_RUN ((GPIOA->IDR&GPIO_Pin_0) ? (GPIOA->BRR=GPIO_Pin_0) : (GPIOA->BSRR=GPIO_Pin_0))
int main(void)
{
LED(1); //拉高LED
LED(0); //拉低LED
while(1)
{
LED_RUN; //翻转LED的IO口,使LED闪烁
}
}
上面代码可以直接拿去用,只需要改下IO端口、Pin脚和宏名就行了,比如我现在想用PB13口控制LED灯:
#define LED(x) ((x==1) ? (GPIOB->BSRR=GPIO_Pin_13) : (GPIOB->BRR=GPIO_Pin_13))
就可以了,控制IO口翻转也同理
#define LED_RUN ((GPIOB->IDR&GPIO_Pin_13) ? (GPIOB->BRR=GPIO_Pin_13) : (GPIOB->BSRR=GPIO_Pin_13))
四、代码解释
1.LED(x)
#define LED(x) ((x==1) ? (GPIOA->BSRR=GPIO_Pin_0) : (GPIOA->BRR=GPIO_Pin_0))
先解释LED(x)的宏定义,这个宏定义是用来直接控制IO高低电平的。
使用了带参宏定义、寄存器和三目运算符的知识。
调用这个宏定义,就会调用((x==1) ? (GPIOA->BSRR=GPIO_Pin_0) : (GPIOA->BRR=GPIO_Pin_0))这一整段代码,在这整段代码中,三目运算符会首先判断x是否等于1,等于1的话就为真,执行GPIOA->BSRR=GPIO_Pin_0这段代码,这段代码的意思就是将PA0电平拉高;否则为假,执行GPIOA->BRR=GPIO_Pin_0这段代码,这段代码的意思就是将PA0电平拉低。
以此达到了拉高拉低的解决方案。
2.LED_RUN
#define LED_RUN ((GPIOA->IDR&GPIO_Pin_0) ? (GPIOA->BRR=GPIO_Pin_0) : (GPIOA->BSRR=GPIO_Pin_0))
LED_RUN(x)的宏定义是用来翻转电平的,这里我用作LED闪烁,也可以有其他用处。
进来先判断PA0脚是高电平还是低电平,并且&对应的引脚,这样就可以在高电平的时候按位返回,低电平的时候返回0。当大于0时判断为真,执行(GPIOA->BRR=GPIO_Pin_0)来将电平拉低;当为0时判断为假,执行(GPIOA->BSRR=GPIO_Pin_0)来将电平拉高。
五、结语
个人感觉比库函数简单方便,还可以用来做一些特殊操作,就比如GPIOx不是同一端口,库函数需要不停的切换GPIOx的x字母,很不方便,特别是在写数组类或者算法类的IO口控制的时候,这样写也能简单明了的知道这个端口是干嘛的,并且比直接宏定义要简洁,直接宏定义要两个才能控制拉高拉低,而这个只需要一个宏定义。文章来源:https://www.toymoban.com/news/detail-821731.html
最后写出来的代码看着很简单,但是实际上写了这么一大篇,本来两句话就可以写完的,还是太照顾了大家了,希望大家都有所收获,有帮助的话就点个赞收藏一下,最好可以关注一下,不定时更新实用的东西。文章来源地址https://www.toymoban.com/news/detail-821731.html
到了这里,关于STM32中使用宏定义来控制IO口的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!