STM32F0利用C语言位域实现仿位带操作,编写STM32通用的sys.h,同正点原子的sys.h函数名和功能一致,方面程序移植

一、前言

平常使用STM32F1和F4,程序不少参考的正点原子的教程,代码里都包含头文件他们的sys.h,这里面主要是实现了stm32的位带操作,位带是啥,博主也没深入研究,但是就是能直接读写GPIO口的某一位,例如:

PAout(1) = 1;//GPIOA Pin1 输出高电平

 if(PAin(2)==1);//判断GPIOA Pin2 是否为高电平

用起来清晰直观,但是最近使用STM32F0,才发现F0没有位带,自然正点原子sys.h里位带操作就没法移植到F0了,那是不是没办法了呢,百度一下发现可以利用位域来实现仿位带操作,下面就来写一个STMF0的sys.h,废话不多说,直接看下面代码。 

 

二、代码实现

代码分三步,可以新建名为sys.h的头文件,放在里面:

(1)因为GPIOX->ODR和GPIOX->IDR寄存器都是低16位有效,所以先定义一个结构体位域,大小为2字节(16位),每一位表示一个IO口。而且要用volatile 防止被编译器优化,如果不加volatile ,像PAout(0)=1;PAout(1)=1;原本先后置1,可能会被优化成GPIOA->ODR=0x03,一起置1了,这可是致命错误,在模拟I2C、SPI时序的时候会出错。

//定义GPIO结构体位域
typedef struct
{
   volatile unsigned short bit0 : 1;
   volatile unsigned short bit1 : 1;
   volatile unsigned short bit2 : 1;
   volatile unsigned short bit3 : 1;
   volatile unsigned short bit4 : 1;
   volatile unsigned short bit5 : 1;
   volatile unsigned short bit6 : 1;
   volatile unsigned short bit7 : 1;
   volatile unsigned short bit8 : 1;
   volatile unsigned short bit9 : 1;
   volatile unsigned short bit10 : 1;
   volatile unsigned short bit11 : 1;
   volatile unsigned short bit12 : 1;
   volatile unsigned short bit13 : 1;
   volatile unsigned short bit14 : 1;
   volatile unsigned short bit15 : 1;

} GPIO_Bit_TypeDef;

(2)将 寄存器地址&(GPIOX->ODR)和& (GPIOX->IDR)强制转换为GPIO_Bit_TypeDef* 指针,并利用宏定义替换为标识符PORTX_OUT或PORTX_IN

#define PORTA_OUT    ((GPIO_Bit_TypeDef *)(&(GPIOA->ODR)))
#define PORTA_IN     ((GPIO_Bit_TypeDef *)(&(GPIOA->IDR)))
#define PORTB_OUT    ((GPIO_Bit_TypeDef *)(&(GPIOB->ODR)))
#define PORTB_IN     ((GPIO_Bit_TypeDef *)(&(GPIOB->IDR)))
#define PORTC_OUT    ((GPIO_Bit_TypeDef *)(&(GPIOC->ODR)))
#define PORTC_IN     ((GPIO_Bit_TypeDef *)(&(GPIOC->IDR)))
#define PORTD_OUT    ((GPIO_Bit_TypeDef *)(&(GPIOD->ODR)))
#define PORTD_IN     ((GPIO_Bit_TypeDef *)(&(GPIOD->IDR)))
#define PORTE_OUT    ((GPIO_Bit_TypeDef *)(&(GPIOE->ODR)))
#define PORTE_IN     ((GPIO_Bit_TypeDef *)(&(GPIOE->IDR)))
#define PORTF_OUT    ((GPIO_Bit_TypeDef *)(&(GPIOF->ODR)))
#define PORTF_IN     ((GPIO_Bit_TypeDef *)(&(GPIOF->IDR)))
#define PORTG_OUT    ((GPIO_Bit_TypeDef *)(&(GPIOG->ODR)))
#define PORTG_IN     ((GPIO_Bit_TypeDef *)(&(GPIOG->IDR)))

(3)利用宏函数和##字符串拼接,实现IO口操作,函数名称和正点原子sys.h里的一致,方便其他程序移植。这里提一下“##”拼接,这是一种宏的特殊符号,##表示把左右字符串拼接在一起

例如:#define GPIO(io) GPIO##io  则 GPIO(A) 会被替换成 GPIOA

在下面这里如果输入n为4,就会变成 bit4,n为8,就会变成bit8

#define PAout(n) (PORTA_OUT->bit##n)
#define PAin(n)  (PORTA_IN->bit##n)
#define PBout(n) (PORTB_OUT->bit##n)
#define PBin(n)  (PORTB_IN->bit##n)
#define PCout(n) (PORTC_OUT->bit##n)
#define PCin(n)  (PORTC_IN->bit##n)
#define PDout(n) (PORTD_OUT->bit##n)
#define PDin(n)  (PORTD_IN->bit##n)
#define PEout(n) (PORTE_OUT->bit##n)
#define PEin(n)  (PORTE_IN->bit##n)
#define PFout(n) (PORTF_OUT->bit##n)
#define PFin(n)  (PORTF_IN->bit##n)
#define PGout(n) (PORTG_OUT->bit##n)
#define PGin(n)  (PORTG_IN->bit##n)

三、例程

实际使用起来就很简单了,和在F1、F4上的一样,以点灯为例,初始化GPIO后,直接赋值就行了

#define LED PAout(4)
void LED_Init(void);

//点灯测试
int main(void)
{
	LED_Init();
	delay_init();
  while (1)
  {
		LED=1;
		delay_ms(500);
		LED=0;
		delay_ms(500);
  }
}

void LED_Init(void)
{
 GPIO_InitTypeDef  GPIO_InitStructure;
 	
 RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);	 //使能PA端口时钟	
 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;				 //LED0-->PB.5 端口配置
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; 		 //输出
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		 //IO口速度为50MHz
 GPIO_InitStructure.GPIO_OType= GPIO_OType_PP;//推挽
 GPIO_InitStructure.GPIO_PuPd= GPIO_PuPd_NOPULL;//无上下拉
 GPIO_Init(GPIOA, &GPIO_InitStructure);	
	//
 GPIO_SetBits(GPIOA,GPIO_Pin_4);						 //PA.4 输出高

}
 

感谢该博主提供的思路http://www.cnblogs.com/endlesscoding/p/7429743.html 

 

四、例程下载

打包上面的例程,sys.h在Driver文件夹里

点击下载

  • 18
    点赞
  • 76
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
STM32H743芯片中实现一个布尔变量表示位操作可以采用以下两种方式: 1. 使用C语言中的位域C语言中的位域可以用来表示位操作,可以使用该类型来定义布尔变量,例如: ```c struct { _Bool bit0 : 1; // 定义一个1位的bit0位域 _Bool bit1 : 1; // 定义一个1位的bit1位域 _Bool bit2 : 1; // 定义一个1位的bit2位域 _Bool bit3 : 1; // 定义一个1位的bit3位域 } flags; flags.bit0 = 1; // 设置bit0位为1 flags.bit1 = 0; // 设置bit1位为0 ``` 需要注意的是,位域的长度不能超过其类型的长度,因此在STM32H743芯片中,可以定义4个1位的布尔变量。 2. 使用宏定义: 另一种实现布尔变量表示位操作的方式是使用宏定义,例如: ```c #define FLAG0 (1 << 0) // 定义第0位的标志位 #define FLAG1 (1 << 1) // 定义第1位的标志位 #define FLAG2 (1 << 2) // 定义第2位的标志位 #define FLAG3 (1 << 3) // 定义第3位的标志位 uint8_t flags = 0; // 定义一个8位的flags变量,初始值为0 flags |= FLAG0; // 设置第0位为1 flags &= ~FLAG1; // 设置第1位为0 ``` 在这种方式下,可以使用位运算符(&、|、~、^)进行位操作,例如设置某一位为1,可以使用或运算符(|),设置某一位为0,可以使用与非运算符(~)。 无论采用哪种方式,都可以在STM32H743芯片中实现布尔变量表示位操作。需要根据实际应用需求进行选择和配置,并进行相应的位运算操作

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

哀歌与世无争

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值