我们首先要了解寄存器的一个特点,他不是只针对一个外设,而是所有的外设都。
就拿GPIO的CRL,ODR寄存器来说
对于GPIOA——GPIOE都有一组功能相同的寄存器只是地址不一样而已A(主要是外设地址不同,比如GPIOA的外设地址和GPIOB的外设地址就不一样,即便寄存器的偏移量一样的),没必要每个寄存器都配置一遍。
这里就引入一个基本操作那就是:使用结构体对GPIO寄存器进行一次封装
主要参考:野火的《开发指南》
typedef unsigned int uint32_t;
typedef unsigned short int uint16_t;
typedef struct
{
uint32_t CRL;
uint32_t CRH;
uint32_t IDR;
uint32_t ODR;
uint32_t BSRR;
uint32_t BRR;
uint32_t LCKR;
}GPIO_TypeDef;
这里还使用了typedef关键字命名了所创建的结构体类型为GPIO_TypeDef
其中结构体成员有7个变量,变量名正是所对应的寄存器名字。
C语言规定了结构体变量的存储空间是连续的(这个正好和我们的寄存器的地址是连续的特点相对应起来。这一点很重要,我们在封装的时候一定要按顺序去封装)。
比如我们定义的这个结构体GPIO_TypeDef。这个结构体的首个寄存器的地址就是CRL寄存器的地址也就是0x4001 0C00(这个地址也是GPIOB这个外设的总线地址),那么结构体第二个成员CRH的地址就是0x4001 0C00再加上一个0x04这个偏移量,为什么?
我们的寄存器是32位的,也就是4个字节为一个寄存器的存储空间,从CRL到CRH加上0x04也就是CRH的地址。其他成员也是相应的去加上偏移量就可以。(注意这个偏移量是相对于总线APB2的基地址的偏移量)
我们这里依然以代码为分析对象
# define PERIPHBASE ((unsigned int)0x40000000)
# define APB1PERIPH_BASE PERIPHBASE
# define APB2PERIPH_BASE (PERIPHBASE + 0x10000)
# define AHBPERIPH_BASE (PERIPHBASE + 0x20000)
# define RCC_BASE (AHBPERIPH_BASE + 0x1000)
# define GPIOB_BASE (APB2PERIPH_BASE + 0x0C00)
# define RCC_APB2ENR *(unsigned int* )(RCC_BASE + 0x18)
typedef unsigned int uint32_t;
typedef unsigned short uint16_t;
typedef struct
{
uint32_t CRL;
uint32_t CRH;
uint32_t IDR;
uint32_t ODR;
uint32_t BSRR;
uint32_t BRR;
uint32_t LCKR;
}GPIO_TypeDef;
# define GPIOB ((GPIO_TypeDef*)(GPIOB_BASE))
#include "stm32f10x.h"
void SystemInit(void);
int main (void)
{
# if 0
*(unsigned int *)0x40021018 |=((1)<<3);
*(unsigned int *)0x40010C0C &=~((1)<<0);
*(unsigned int *)0x40010C00 |=((1)<<(4*0));
#elif 0
RCC_APB2ENR |= ((1)<<3);
GPIOB_CRL |= ((1)<<(4*0));
GPIOB_ODR &= ~(unsigned int)(1<<0);
#elif 1
RCC_APB2ENR |= ((1)<<3);
GPIOB->CRL |= ((1)<<(4*0));
GPIOB->ODR &= ~(unsigned int)(1<<0);
#endif
}
void SystemInit(void)
{
}
这里不得不重新说明一下,什么是结构体。以便更好的理解和使用它:
这里我看的是B站UP主“杜远超官方频道”的视频,可以直接搜索结构体就能看到。我是很推荐这个视频的,希望帮到你!!
下面声明一个结构体类型:
# include <stdio.h>
struct Student
{
int id;
int age;
char*name;
float score;
};
struct Emptystruct
{
};
int main ()
{
}
下面声明一个匿名的结构体类型:
# include <stdio.h>
struct
{
int id;
int age;
char*name;
float score;
}stu1,stu2;
int main ()
{
return 0;
}
下面我们引入typedef:
第一种用法
# include <stdio.h>
struct Student
{
int id;
int age;
char*name;
float score;
};
typedef struct Stdent Stdent;
int main ()
{
Student stu1;
return 0;
}
第二种用法
# include <stdio.h>
typedef struct Stdent
{
int id;
int age;
char*name;
float score;
}Student;
int main ()
{
Student stu1;
return 0;
}
下面介绍结构体的嵌套
# include <stdio.h>
typedef struct Birthday
{
int year;
int month;
int day;
}Birthday;
typedef struct Stdent
{
int id;
int age;
char*name;
float score;
Birthday bitthday;
}Student;
int main ()
{
Student stu;
stu.birthday.year = 1996;
return 0;
}
结构体变量
声明结构体变量的方式
方式1
# include <stdio.h>
typedef struct Birthday
{
int year;
int month;
int day;
}Birthday;
typedef struct Stdent
{
int id;
int age;
char*name;
float score;
Birthday bitthday;
}Student;
int main ()
{
Student stu1;
Student stu2;
return 0;
}
声明结构体变量的方式
方式2
# include <stdio.h>
typedef struct Birthday
{
int year;
int month;
int day;
}Birthday;
typedef struct Stdent
{
int id;
int age;
char*name;
float score;
Birthday bitthday;
}Student,stu3;
int main ()
{
Student stu1;
Student stu2;
return 0;
}
结构体变量的赋值
# include <stdio.h>
typedef struct Birthday
{
int year;
int month;
int day;
}Birthday;
typedef struct Stdent
{
int id;
int age;
char*name;
float score;
Birthday bitthday;
}Student,stu3;
int main ()
{
Student stu1 = {1001,26,"李明",100,
{1996,10,20}};
Student stu2 = {1002,22,"李华",99,
{2000,10,20}};
return 0;
}
如何去创建结构体变量
# include <stdio.h>
typedef struct Birthday
{
int year;
int month;
int day;
}Birthday;
typedef struct Stdent
{
int id;
int age;
char*name;
float score;
Birthday bitthday;
}Student,stu3;
int main ()
{
Student stu1;
Student stu2;
return 0;
}
结构体成员的调用
# include <stdio.h>
typedef struct Birthday
{
int year;
int month;
int day;
}Birthday;
typedef struct Stdent
{
int id;
int age;
char*name;
float score;
Birthday bitthday;
}Student,stu3;
int main ()
{
Student stu1 = {1001,26,"李明",100,
{1996,10,20}};
Student stu2 = {1002,22,"李华",99,
{2000,10,20}};
printf("学号:%d 姓名:%s 年龄:%d 成绩:%0.2f 生日:%d-%d-%d",stu1.id,stu1.name,stu1.age,stu1.score,stu1.Birthday.year,stu1.Birthday.month,syu1.Birthday.day);
return 0;
}
显然,结构体的访问格式就是,“结构体名 . 结构体变量”的形式。
如果是嵌套的话也是使用.去调用。
程序优化:单独定义一个打印函数
# include <stdio.h>
typedef struct Birthday
{
int year;
int month;
int day;
}Birthday;
typedef struct Stdent
{
int id;
int age;
char*name;
float score;
Birthday bitthday;
}Student,stu3;
void PrintfStudentInfo(Student stu)
{
printf("学号:%d 姓名:%s 年龄:%d 成绩:%0.2f 生日:%d-%d-%d",stu.id,stu.name,stu.age,stu.score,stu.Birthday.year,stu.Birthday.month,syu.Birthday.day);
}
int main ()
{
Student stu1 = {1001,26,"李明",100,
{1996,10,20}};
Student stu2 = {1002,22,"李华",99,
{2000,10,20}};
PrintfStudentInfo(Student stu1);
return 0;
}
上面的代码还是有他的局限性,想想看我们即便是定义了一个打印函数,但是对于系统来说,我仍然是拷贝了一份打印的信息并封存在了函数中。
所以引出下面的使用结构体指针。
使用结构体指针
# include <stdio.h>
typedef struct Birthday
{
int year;
int month;
int day;
}Birthday;
typedef struct Stdent
{
int id;
int age;
char*name;
float score;
Birthday bitthday;
}Student,stu3;
void PrintfStudentInfo(Student *p_stu)
{
printf("学号:%d 姓名:%s 年龄:%d 成绩:%0.2f 生日:%d-%d-%d",p_stu.id,p_stu.name,p_stu.age,p_stu.score,p_stu.Birthday.year,p_stu.Birthday.month,p_stu.Birthday.day);
}
int main ()
{
Student stu1 = {1001,26,"李明",100,
{1996,10,20}};
Student stu2 = {1002,22,"李华",99,
{2000,10,20}};
Student*pstu = &stu1;
PrintfStudentInfo(pstu);
return 0;
}
上面的代码存在一个致命错误!!!!!
void PrintfStudentInfo(Student *p_stu)
{
printf("学号:%d 姓名:%s 年龄:%d 成绩:%0.2f 生日:%d-%d-%d",p_stu.id,p_stu.name,p_stu.age,p_stu.score,p_stu.Birthday.year,p_stu.Birthday.month,p_stu.Birthday.day);
}
注意上面这一行代码,我们的c语言规定了,如果我们使用的是结构体指针,要求我们在访问结构体成员的时候不再使用“.”。而是改用“->”
正确的写法如下所示:
void PrintfStudentInfo(Student *p_stu)
{
printf("学号:%d 姓名:%s 年龄:%d 成绩:%0.2f 生日:%d-%d-%d",p_stu>id,p_stu->name,p_stu->age,p_stu->score,p_stu->Birthday.year,p_stu->Birthday.month,p_stu->Birthday.day);
}
//注意细节,我们在使用
p_stu->Birthday.month
# include <stdio.h>
typedef struct Birthday
{
int year;
int month;
int day;
}Birthday;
typedef struct Stdent
{
int id;
int age;
char*name;
float score;
Birthday bitthday;
}Student,stu3;
void PrintfStudentInfo(Student *p_stu)
{
printf("学号:%d 姓名:%s 年龄:%d 成绩:%0.2f 生日:%d-%d-%d",p_stu.id,p_stu.name,p_stu.age,p_stu.score,p_stu.Birthday.year,p_stu.Birthday.month,p_stu.Birthday.day);
}
int main ()
{
Student stu1 = {1001,26,"李明",100,
{1996,10,20}};
Student stu2 = {1002,22,"李华",99,
{2000,10,20}};
Student*pstu = &stu1;
PrintfStudentInfo(pstu);
pstu = &stu2;
PrintfStudentInfo(pstu);
return 0;
}
本篇完。。。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)