单片机io地址固定,想要统一管理就需要面向对象编程。
bit控制:
struct Byte_Type
{
bool X0;
bool X1;
bool X2;
bool X3;
bool X4;
bool X5;
bool X6;
bool X7;
}
端口控制:
struct Out_Type
{
Byte_Type PA; // PA拆成 8 Bit
*Byte_Type 0x81 PB; // 对象要映射到地址上
Byte_Type PC;
Byte_Type PD;
Byte_Type PE;
Byte_Type PF;
Byte_Type PG;
Byte_Type PH;
}
这样 PA的成员有8个 【PA.X7】
赋值 PA.X7=True;
对象映射地址:【从右到左】
int *P;
对象映射地址:
实际就是把对象的类型,对齐到内存的地址上。
【C语言符号优先级】//从手册上看是【先右到左】
Type_B* Type_A*
多级指针; Type_D* Type_C* Type_B* Type_A*
方向是从右到左。先把总内存切割成【Type_A】类型的每块,然后再去定位到地址位置。
【就相当于你有1000元,换成2元一张的钞票,能换多少张,钞票的张数编号就是地址编号】
【 1000元,换成5毛一张的钞票,能换多少张,钞票的张数编号就是地址编号】
位域:
这个和位带相反。位带是把Byte膨胀成8个int类型。
struct
{
unsigned int widthValidated;
unsigned int heightValidated;
} statusA;
struct
{
unsigned int widthValidated : 1; //表示长度 1bit
unsigned int heightValidated : 3; //表示长度 3bit
} statusB;
statusB 学生C;
学生C.heightValidated = 0xFF; // 输出结果是7【因为长度是3bit】
用二进制控制LED灯:
主要是希望所见即所得:
LED = 0B00001111; //0x0f 在C#中的二进制写法。 八进制的话【前面加0】
Led = 2#00001111;
led = 16#000F;
led = 0x0F;
单片机io控制:
#ifndef __SYS_H
#define __SYS_H
#include "stm32f4xx.h"
//位带操作,实现51类似的GPIO控制功能
//具体实现思想,参考<<CM3权威指南>>第五章(87页~92页).
//IO口操作宏定义
#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))
//IO口地址映射
#define PA GPIOA->ODR //0x40000000+0x00020000+0x0000(A)+0x14(ODR)
#define PB GPIOB->ODR //0x40000000+0x00020000+0x0400(B)+0x14(ODR)
#define PC GPIOC->ODR //
#define PD GPIOD->ODR //
#define PE GPIOE->ODR //
#define PF GPIOF->ODR //
#define PG GPIOG->ODR //
#define PH GPIOH->ODR //
#define PI GPIOI->ODR //
#define PJ GPIOJ->ODR //
#define PK GPIOK->ODR //
#define PAi GPIOA->IDR //外设端口输入
#define PBi GPIOB->IDR //
#define PCi GPIOC->IDR //
#define PDi GPIOD->IDR //
#define PEi GPIOE->IDR //
#define PFi GPIOF->IDR //
#define PGi GPIOG->IDR //
#define PHi GPIOH->IDR //
#define PIi GPIOI->IDR //
#define PJi GPIOJ->IDR //
#define PKi GPIOK->IDR //
//IO口操作,只对单一的IO口!
//确保n的值小于16!
#define PAout(n) BIT_ADDR(GPIOA->ODR,n) //输出
#define PAin(n) BIT_ADDR(GPIOA->IDR,n) //输入
#define PBout(n) BIT_ADDR(GPIOB->ODR,n) //输出
#define PBin(n) BIT_ADDR(GPIOB->IDR,n) //输入
#define PCout(n) BIT_ADDR(GPIOC->ODR,n) //输出
#define PCin(n) BIT_ADDR(GPIOC->IDR,n) //输入
#define PDout(n) BIT_ADDR(GPIOD->ODR,n) //输出
#define PDin(n) BIT_ADDR(GPIOD->IDR,n) //输入
#define PEout(n) BIT_ADDR(GPIOE->ODR,n) //输出
#define PEin(n) BIT_ADDR(GPIOE->IDR,n) //输入
#define PFout(n) BIT_ADDR(GPIOF->ODR,n) //输出
#define PFin(n) BIT_ADDR(GPIOF->IDR,n) //输入
#define PGout(n) BIT_ADDR(GPIOG->ODR,n) //输出
#define PGin(n) BIT_ADDR(GPIOG->IDR,n) //输入
void NVIC_Configuration(void);//设置NVIC中断分组2:2位抢占优先级,2位响应优先级
#endif
//GPIO_InitTypeDef GPIO_InitStructure;//引脚参数
//
// RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE); //使能 端口时钟
输出 初始化
// GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15 ; // 端口配置
// 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_UP;//上拉
//
// GPIO_Init(GPIOD, &GPIO_InitStructure); //根据设定参数初始化
// GPIO_SetBits(GPIOD,GPIO_Pin_0|GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15);
/
#include "sys.h"
#include "misc.h"
//
void NVIC_Configuration(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置NVIC中断分组2:2位抢占优先级,2位响应优先级
}
分析:
//IO口操作宏定义
#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))
BIT_ADDR(addr, bitnum)// 顶层
MEM_ADDR(BITBAND(addr, bitnum)) // 顶层-1
MEM_ADDR(((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2)) ) // 顶层-2
*((volatile unsigned long *)(【顶层-2】))
完全形态:
*((volatile unsigned long *)
(addr & 0xF0000000) +0x2000000+ ((addr &0xFFFFF)<<5) + (bitnum<<2)
类型指针和指针的区别:
类型指针和指针之间的区别在于它们所指向的数据类型不同。
类型指针是指向特定数据类型的指针,
而指针则是指向任意数据类型的指针。
类型指针有特定的数据类型,例如char指针指向char类型的数据,int指针指向int类型的数据。
在做指针运算时,类型指针会按照数据类型所占用的内存空间的字节数的倍数关系进行移动。
而指针则可以指向任意类型的数据,无论是char、int还是其他类型。
指针本身只存储一个地址值,不关心指向的数据类型。
在C语言中,指针加1后的偏移量取决于指针所指向的数据类型的字节大小。例如,如果一个指针指向一个int类型的变量,那么指针加1后的偏移量就是4个字节(32个比特),因为int类型在大多数系统中占据4个字节的内存空间。