内容:stm32f103实现类似51单片机一整排IO的编程方式
文章相关 | 版本 |
---|---|
KIO库 | 点击下载KIO: 解压密码:176145 |
proteus | 8.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的接口。
作为一个新手,实在是不能忍受这种非人性化的设计。 于是决定自己动手去实现这个平凡的接口,在经历了漫长的调试后,我们终于实现了这样一个接口,下面是源代码分享缓解。
(二)代码部分 1:.h文件在此之前,我先向着大家介绍一个我实现的一个简单的库:KIO。
此库是我在学习stm32f103的时候写的一个库,对应了官方库中的IO和rcc俩个库的简单的一些函数实现。
由于我觉得自己写的挺方便的,就用到了现在。
提示:本文章的内容不一定需要用到KIO的库,但是我把接口函数的实现写进了KIO内部,只想用接口不想深入学习的的同学可以直接主页下载该库,并对比下文的使用方法。
#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
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)