论坛元老
 
- 积分
- 10653
- 金钱
- 10653
- 注册时间
- 2017-4-14
- 在线时间
- 2780 小时
|
本帖最后由 nashui_sx 于 2021-2-27 13:46 编辑
STM32F030F4不支持位带操作,最近总是来回切换stm32f1 f0,同样写的库 引脚初始化改来改去挺烦的,就想弄个方案解决,给大家分享下
1.普通大家用的模拟位带操作
typedef struct _16_Bits_Struct
{
u16 bit0 : 1;
u16 bit1 : 1;
u16 bit2 : 1;
u16 bit3 : 1;
u16 bit4 : 1;
u16 bit5 : 1;
u16 bit6 : 1;
u16 bit7 : 1;
u16 bit8 : 1;
u16 bit9 : 1;
u16 bit10 : 1;
u16 bit11 : 1;
u16 bit12 : 1;
u16 bit13 : 1;
u16 bit14 : 1;
u16 bit15 : 1;
} Bits_16_TypeDef;
//使用
#define LED_PORT GPIOA
#define LED_PIN GPIO_Pin_4
#define LED0 (((Bits_16_TypeDef *)(&(LED_PORT->ODR)))->bit4)//输出
#define KEY1 (((Bits_16_TypeDef *)(&(KEY_PORT->IDR)))->bit3)//输入[/mw_shl_code]
这样就是往常常用的模拟位带操作的方法,但是给正点原子的#define PAout(n) 还是有点不一样,头文件宏定义还是要改,就想着能不能改进下,下面两行代码,兼容原子的代码
#define LED0 (((Bits_16_TypeDef *)(&(LED_PORT->ODR)))->bit4)//输出
#define KEY1 (((Bits_16_TypeDef *)(&(KEY_PORT->IDR)))->bit3)//输入
2.改进位带操作
分析 #define LED0 PAout(4) 和#define LED0 (((Bits_16_TypeDef *)(&(GPIOA->ODR)))->bit4)的差异
也就是4和->bit4的差异,这俩看着有规律可是怎么都替换不了
后来想起来二进制转10进制的方法 //用n替换"0x##n"中的"n"的方法,就尝试了下,确实可以
以#define PAout(n) (((Bits_16_TypeDef *)(&(GPIOA->ODR)))->bit##n) 为例
PAout(n)中的n 在 (((Bits_16_TypeDef *)(&(GPIOA->ODR)))->bit##n)中 会替换##n
这样PAout(1)就等价于执行(((Bits_16_TypeDef *)(&(GPIOA->ODR)))->bit1),就兼容原子的代码了
下面代码放到f0的sys.h 就能和f1 f4的外带操作一样了
//方案2
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
typedef struct _16_Bits_Struct
{
u16 bit0 : 1;
u16 bit1 : 1;
u16 bit2 : 1;
u16 bit3 : 1;
u16 bit4 : 1;
u16 bit5 : 1;
u16 bit6 : 1;
u16 bit7 : 1;
u16 bit8 : 1;
u16 bit9 : 1;
u16 bit10 : 1;
u16 bit11 : 1;
u16 bit12 : 1;
u16 bit13 : 1;
u16 bit14 : 1;
u16 bit15 : 1;
} Bits_16_TypeDef;
//用n替换"0x##n"中的"n"
#define PAout(n) (((Bits_16_TypeDef *)(&(GPIOA->ODR)))->bit##n) //输出
#define PAin(n) (((Bits_16_TypeDef *)(&(GPIOA->IDR)))->bit##n) //输入
#define PBout(n) (((Bits_16_TypeDef *)(&(GPIOB->ODR)))->bit##n) //输出
#define PBin(n) (((Bits_16_TypeDef *)(&(GPIOB->IDR)))->bit##n) //输入
#define PCout(n) (((Bits_16_TypeDef *)(&(GPIOC->ODR)))->bit##n) //输出
#define PCin(n) (((Bits_16_TypeDef *)(&(GPIOC->IDR)))->bit##n) //输入
#define PDout(n) (((Bits_16_TypeDef *)(&(GPIOD->ODR)))->bit##n) //输出
#define PDin(n) (((Bits_16_TypeDef *)(&(GPIOD->IDR)))->bit##n) //输入
#define PEout(n) (((Bits_16_TypeDef *)(&(GPIOE->ODR)))->bit##n) //输出
#define PEin(n) (((Bits_16_TypeDef *)(&(GPIOE->IDR)))->bit##n) //输入
#define PFout(n) (((Bits_16_TypeDef *)(&(GPIOF->ODR)))->bit##n) //输出
#define PFin(n) (((Bits_16_TypeDef *)(&(GPIOF->IDR)))->bit##n) //输入
#define PGout(n) (((Bits_16_TypeDef *)(&(GPIOG->ODR)))->bit##n) //输出
#define PGin(n) (((Bits_16_TypeDef *)(&(GPIOG->IDR)))->bit##n) //输入
至此,以后f1 f0的代码就能直接通用了
以下是附带的,引脚初始化通用代码,与位带操作相结合完美解决f0 f1 f4外设代码移植的通用性
具体是在f0 f1 f4 sys.h sys.c 分别添加一下代码(附带优点,自动识别要初始化的时钟总线)
里面用到的一个函数power 指数次方,用于计算时钟总线
u32 Power(u32 x,u32 y){u32 mul = 1,i;for(i = 0;i<y;i++)mul = mul * x;return mul;}
f0的
//sys.h
typedef enum
{
GPIO_FK_IN=0, //浮空输入
GPIO_AD_IN=1, //AD输入
GPIO_KL_OUT=2, //开漏输出 可以读IO输入电平变化,实现C51的IO双向功能,就不需要切换输入输出了,但需要外部上拉电阻
GPIO_KL_AF_OUT=3,//开漏复用
GPIO_TW_OUT=4, //推挽输出
GPIO_TW_AF_OUT=5,//推挽复用
GPIO_P_NO=6, //不上下拉
GPIO_P_UP=7, //上拉
GPIO_P_DOWN=8, //下拉
GPIO_2MHz=9,
GPIO_10MHz=10,
GPIO_25MHz=10,//用GPIO_10MHz替代
GPIO_50MHz=12,
GPIO_100MHz=12//用GPIO_50MHz替代
}GPIO_My_TypeDef;
void My_GPIO_Init(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin,GPIO_My_TypeDef mode,GPIO_My_TypeDef up_down,GPIO_My_TypeDef speed);
//sys.c
//stm32 通用外设初始化方案,方便不同芯片移植
void My_GPIO_Init(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin,GPIO_My_TypeDef mode,GPIO_My_TypeDef up_down,GPIO_My_TypeDef speed)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHBPeriphClockCmd(Power(2,((uint32_t)GPIOx-(uint32_t)GPIOA)/0x0400)*(uint32_t)RCC_AHBPeriph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin;
if(mode==GPIO_FK_IN) GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
if(mode==GPIO_KL_OUT||mode==GPIO_TW_OUT) GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
if(mode==GPIO_KL_AF_OUT||mode==GPIO_TW_AF_OUT) GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
if(mode==GPIO_AD_IN) GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
if(mode==GPIO_TW_OUT||mode==GPIO_TW_AF_OUT) GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
if(mode==GPIO_KL_OUT||mode==GPIO_KL_AF_OUT) GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
if(up_down==GPIO_P_NO) GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
if(up_down==GPIO_P_UP) GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
if(up_down==GPIO_P_DOWN) GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;
if(speed==GPIO_2MHz) GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
if(speed==GPIO_10MHz) GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
if(speed==GPIO_25MHz) GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;//用GPIO_10MHz替代
if(speed==GPIO_50MHz) GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
if(speed==GPIO_100MHz) GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//用GPIO_50MHz替代
GPIO_Init(GPIOx, &GPIO_InitStructure);
}
f1
//sys.h
typedef enum
{
GPIO_FK_IN=0,
GPIO_AD_IN=1,
GPIO_KL_OUT=2,
GPIO_KL_AF_OUT=3,
GPIO_TW_OUT=4,
GPIO_TW_AF_OUT=5,
GPIO_P_NO=6,
GPIO_P_UP=7,
GPIO_P_DOWN=8,
GPIO_2MHz=9,
GPIO_10MHz=10,
GPIO_25MHz=10,//用GPIO_10MHz替代
GPIO_50MHz=12,
GPIO_100MHz=12//用GPIO_50MHz替代
}GPIO_My_TypeDef;
void My_GPIO_Init(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin,GPIO_My_TypeDef mode,GPIO_My_TypeDef up_down,GPIO_My_TypeDef speed);
//sys.c
//stm32 通用外设初始化方案,方便不同芯片移植
void My_GPIO_Init(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin,GPIO_My_TypeDef mode,GPIO_My_TypeDef up_down,GPIO_My_TypeDef speed)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(Power(2,((uint32_t)GPIOx-(uint32_t)GPIOA)/0x0400+2), ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin;
if(mode==GPIO_AD_IN) GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
if(mode==GPIO_FK_IN && up_down==GPIO_P_NO) GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
if(mode==GPIO_FK_IN && up_down==GPIO_P_DOWN) GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
if(mode==GPIO_FK_IN && up_down==GPIO_P_UP) GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
if(mode==GPIO_KL_OUT) GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
if(mode==GPIO_TW_OUT) GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
if(mode==GPIO_KL_AF_OUT) GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
if(mode==GPIO_TW_AF_OUT) GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
if(speed==GPIO_2MHz) GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
if(speed==GPIO_10MHz) GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
if(speed==GPIO_25MHz) GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;//用GPIO_10MHz替代
if(speed==GPIO_50MHz) GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
if(speed==GPIO_100MHz) GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//用GPIO_50MHz替代
GPIO_Init(GPIOx, &GPIO_InitStructure);
}
f4的
//sys.h
typedef enum
{
GPIO_FK_IN=0, //浮空输入
GPIO_AD_IN=1, //AD输入
GPIO_KL_OUT=2, //开漏输出 可以读IO输入电平变化,实现C51的IO双向功能,就不需要切换输入输出了,但需要外部上拉电阻
GPIO_KL_AF_OUT=3,//开漏复用
GPIO_TW_OUT=4, //推挽输出
GPIO_TW_AF_OUT=5,//推挽复用
GPIO_P_NO=6, //不上下拉
GPIO_P_UP=7, //上拉
GPIO_P_DOWN=8, //下拉
GPIO_2MHz=9,
GPIO_10MHz=9, //用GPIO_2MHz替代
GPIO_25MHz=11,
GPIO_50MHz=12,
GPIO_100MHz=13
}GPIO_My_TypeDef;
void My_GPIO_Init(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin,GPIO_My_TypeDef mode,GPIO_My_TypeDef up_down,GPIO_My_TypeDef speed);
//sys.c
//stm32 通用外设初始化方案,方便不同芯片移植
void My_GPIO_Init(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin,GPIO_My_TypeDef mode,GPIO_My_TypeDef up_down,GPIO_My_TypeDef speed)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(Power(2,((uint32_t)GPIOx-(uint32_t)GPIOA)/0x0400), ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin;
if(mode==GPIO_FK_IN) GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
if(mode==GPIO_KL_OUT||mode==GPIO_TW_OUT) GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
if(mode==GPIO_KL_AF_OUT||mode==GPIO_TW_AF_OUT) GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
if(mode==GPIO_AD_IN) GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
if(mode==GPIO_TW_OUT||mode==GPIO_TW_AF_OUT) GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
if(mode==GPIO_KL_OUT||mode==GPIO_KL_AF_OUT) GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
if(up_down==GPIO_P_NO) GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
if(up_down==GPIO_P_UP) GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
if(up_down==GPIO_P_DOWN) GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;
if(speed==GPIO_2MHz ) GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
if(speed==GPIO_10MHz ) GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;//用GPIO_2MHz替代
if(speed==GPIO_25MHz ) GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz;
if(speed==GPIO_50MHz ) GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
if(speed==GPIO_100MHz) GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_Init(GPIOx, &GPIO_InitStructure);
}
使用方法:(自动识别要初始化的时钟总线)
#define LED_PORT GPIOA
#define LED_PIN GPIO_Pin_4//能或组合引脚
led初始化My_GPIO_Init(LED_PORT,LED_PIN,GPIO_TW_OUT,GPIO_P_DOWN,GPIO_10MHz);//推挽输出 下拉 10m
#define KEY_PORT GPIOA
#define KEY_PIN GPIO_Pin_3//能或组合引脚
key初始化My_GPIO_Init(KEY_PORT,KEY_PIN,GPIO_FK_IN,GPIO_P_UP,GPIO_50MHz);//浮空输入 上拉 50m
这样以后外设的代码就能兼容f0 f1 f4了,直接复制过去,完美直接用
欢迎大家提提意见
|
|