stm32f103<1>:实现IO口的十六进制整排编程

stm32f103<1>:实现IO口的十六进制整排编程,第1张

STM32F103进阶

内容:stm32f103实现类似51单片机一整排IO的编程方式

文章相关版本
KIO库点击下载KIO:

解压密码:176145
proteus8.13

学习目录
  • (一)内容介绍
  • (二)代码部分
    • 1:.h文件
    • 2:.C文件
    • 3:main文件:简单实现走马灯
      • 1:配置IO口:.c文件
      • 2:配置IO口:.h文件
      • 3:主函数:main文件
    • 4:proteus简单仿真
  • (三)结束语

(一)内容介绍

   2022年4月3日,亿只萌新在下定决心准备做他的毕业设计的时候,突然发现STM32103单片机官方库好像没有提供51单片机这种↓↓

#define LED P2

直接 *** 控整排IO的接口。


    作为一个新手,实在是不能忍受这种非人性化的设计。


于是决定自己动手去实现这个平凡的接口,在经历了漫长的调试后,我们终于实现了这样一个接口,下面是源代码分享缓解。


在此之前,我先向着大家介绍一个我实现的一个简单的库:KIO。


此库是我在学习stm32f103的时候写的一个库,对应了官方库中的IO和rcc俩个库的简单的一些函数实现。



由于我觉得自己写的挺方便的,就用到了现在。



提示:本文章的内容不一定需要用到KIO的库,但是我把接口函数的实现写进了KIO内部,只想用接口不想深入学习的的同学可以直接主页下载该库,并对比下文的使用方法。


(二)代码部分 1:.h文件
#include "myrcc.h" //KIO库中的头文件,没有KIO库的可以不用包含此头文件

/*ODR地址映射 ,由偏移地址+基地址算出算出*/
#define P_Mask (0x400)
#define P_ODR   (0x40010800+12)
#define P_IDR   (0x40010800+8)
#define P_ODR_IDR_MASK(N,P_O_I)  ((P_O_I)+((P_Mask)*(N)))//计算硬件地址

/*---以下部分可以不看,改接口的实现主要由上面的宏实现-------------*/
/*下面为真实的物理地址ODR代表输出,IDR代表输入*/
#define PA_ODR_Addr    (0x40010800+12) //0x4001080C 
#define PB_ODR_Addr    (0X40010C00+12) //0x40010C0C 
#define PC_ODR_Addr    (0x40011000+12) //0x4001100C 
#define PD_ODR_Addr    (0x40011400+12) //0x4001140C 
#define PE_ODR_Addr    (0x40011800+12) //0x4001180C 
#define PF_ODR_Addr    (0x40012000+12) //0x40011A0C    
#define PG_ODR_Addr    (0x40012000+12) //0x40011E0C    
#define PA_IDR_Addr    (0x40010800+8) //0x40010808 
#define PB_IDR_Addr    (0X40010C00+8) //0x40010C08 
#define PC_IDR_Addr    (0x40011000+8) //0x40011008 
#define PD_IDR_Addr    (0x40011400+8) //0x40011408 
#define PE_IDR_Addr    (0x40011800+8) //0x40011808 
#define PF_IDR_Addr    (0x40012000+8) //0x40011A08 
#define PG_IDR_Addr    (0x40012000+8) //0x40011E08 

/*1:拼接地址字符*/
#define P_SET(X,TYPE) P##X##_##TYPE##_Addr 
#define OUT ODR
#define IN IDR
/*---------------不看到此处为止---------------------------*/
/*2:计算物理地址:该部分来源自官方库实现*/
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2)) 
#define MEM_ADDR(addr)  *((volatile unsigned long  *)(addr)) 
#define BIT_ADDR(addr, bitnum)   MEM_ADDR(BITBAND(addr, bitnum)) 
 //*((volatile unsigned long  *)(42210180~42,210,240) 
//IDR(4221 0160)

/*3:查看定位:便于开发者的跳转函数*/
#define CHEEK_IO_DEFINE_TABLE(LOOK) ((void)0);//查看定位

/*4:最终汇总,以上所有的方式都在下面俩个宏中汇总*/
#define P(Type,Px,n) BIT_ADDR(P_SET(Px,Type),n) //定义方式1
#define P2(addr,n) BIT_ADDR(addr,n) //定义方式2

/*5:IO 排口*/
typedef enum{
  _PA_OUT = 0,_PB_OUT,_PC_OUT,_PD_OUT,_PE_OUT,_PF_OUT,_PG_OUT,
  _PA_IN,_PB_IN,_PC_IN,_PD_IN,_PE_IN,_PF_IN,_PG_IN,
}_PA_ALL;

/*6:函数接口申明*/
void Io_ALL_Keil(_SInt intput,_PA_ALL a);//整排IO的编辑的接口
2:.C文件

/*实现部分相对来说比较简单*/
/*调用方式:Io_ALL_Keil(X,_PA_OUT)
		对PA一整排进行编程
		详情请看下述main.c文件
*/
void Io_ALL_Keil(_SInt intput,_PA_ALL a)
{
    _Char n = 0;
    unsigned long int addr;
    _Char out = 0;
    if(a < _PF_OUT)
    {
        addr = P_ODR_IDR_MASK(a,P_ODR);
    }
    else if(a == _PG_OUT)
    {
        addr = P_ODR_IDR_MASK(a-1,P_ODR);
    }
    else if(a>6 && a<13)
    {
        addr = P_ODR_IDR_MASK(a-7,P_IDR);
    }
    else if(a == 13)
    {
        addr = P_ODR_IDR_MASK(a-7-1,P_IDR);
    }
    else
    {
     printf("%s\n","error to io_all_set");
      return ;
    }
    //有了addr
    while(n<16)//一个字节一个字节的判断
    {
        out= intput>>15;
        intput = intput<<1;
        if(out == 1)//设置为高
        {
            P2(addr,n) = 1;
        }
        else if(out == 0)//设置为低
        {
            P2(addr,n) = 0;
        }
        n++;
    }
    printf("OKJ");
}
3:main文件:简单实现走马灯 1:配置IO口:.c文件
/*提示:此配置方式为KIO库同学的专属配置方式
		,普通同学可以用传统的配置方式*/
void IO_Need_Init(void)
{
  CHEEK_MODE_TABLE("Look the Mode_SPEED");
  CHEEK_APB2_TABLE("Look the APB2");
//初始化A端口的1,4,5,6,7口
  init_my_all(PA, _Pany("1,4,5,6,7,"), PP_OUT_10MHZ, APB2_Set_PA, IO_SET_High); 
//初始化按键配置
	//init_my_all(PB, _Pany("1,2,3,4,5,6,7,"), P_IN, APB2_Set_PB, IO_SET_Button);       
//PB 整排IO初始化配置
  init_my_all(PB ,IO_Pin_0_15, PP_OUT_10MHZ, APB2_Set_PB, IO_SET_High); 
}
2:配置IO口:.h文件
#include "sys.h"
#include "io.h" //KIO同学专用库
/*--------------------------------------------*/
#define People_Feel  P(IN ,B,1) //普通按键
#define Com_Button   P(IN ,B,2) //普通按键
#define LED_Warning  P(OUT,A,1) //小灯泡

//官方定义方式:#define LED PBout(5)

#define IN1          P(OUT,A,4) 
#define IN2          P(OUT,A,5)
#define IN3          P(OUT,A,6)
#define IN4          P(OUT,A,7)

//PB口整排定义:这里用到了接口所以没有整排的官方方式○☆○
#define LED(X)    Io_ALL_Keil(X,_PB_OUT);//PB整排设置为输出模式
/*--------------------------------------------*/

void IO_Need_Init(void);//初始化函数申明


3:主函数:main文件
#include "Unit.h"//我把工程所有的头文件都包含进了这个头文件,大家可以自己一个一个列出来,那个函数在哪个头文件中,就包含哪个头文件就行了
//由于博主的工程项目头问价较多,就不复制出来了

//延时函数
void DE()
{
  TIM_Cmd(TIM2, ENABLE);//打开定时器
  while(getTime(GET_SEC)<2);
  /*定时2秒
  【getTime(GET_SEC)该函数为博主自己写的函数,主要是获取定时器中的标志位的增量】
  
  实现方法就是函数return这个标志位就OK了
  */
  sec =0;
  TIM_Cmd(TIM2, DISABLE);//关闭定时器
}

//主函数
int main(void)
{ 
  unsigned short int WC = 0xffff;//定义一整排的 *** 作变量WC
  
  uart_init(9600);                /* 串口初始化      */
	TIM2_Int_Init(4999,249);       /* 定时器初始化   */
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); /*优先级*/
	IO_Need_Init(); //初始化IO
	while(1)
	{
    LED(WC = WC>>1);//WC初始值 = oxffff,转化为二进制也就是对应了0~15共16个IO口
    DE();//函数函数
  }
  return 1;
}
4:proteus简单仿真

以下为运行大概4秒后的截图,可以看到,从0-15的小灯(由于懒只画了五个)已经一次熄灭了两个小灯。


很抱歉没有gif工具,这里只能放一张静态图片。



(三)结束语

   以上就是今天所要分享的内容了
   学习路漫漫,我们仍需负重前行……
   为此博主新创建了一个群,期待你们的加入:

欢迎加入我们的大家庭:928357277

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/567513.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-09
下一篇 2022-04-09

发表评论

登录后才能评论

评论列表(0条)

保存