第一章 外设中变量的组成

第一章 外设中变量的封装和引用



前言

学习单片机也快有三年了,说真的感觉还是对编写代码很模糊,没有豁然开朗的感觉。但不管怎么说,虽然自己还是什么都不会,但也积累了不少经验。

感觉单片机编程甚至PLC编程最基础的还是对变量的使用,可以说定义变量是编程的第一步。
C语言中规定变量必须先定义后使用,一次性将所有的变量定义或者声明。


一、变量和常量

赋值表达式:变量=常量
例如:a=10
a就是变量,10就是常量。

类似的还有很多表达式:算数运算符(±*/%)+位运算符(<<&|>>),他们与赋值=构成很多复合赋值表达式,运算对象就是变量和常量。

二、struct

有没有什么东西,可以把需要的变量都给放一块,应该有,就是结构体。

1.结构体

一组相同或不同数据类型构成的新的数据类型

2.头文件定义和声明

在#include“uarts.h”里面结构体定义和声明

typedef struct 
{
	unsigned char volatile Tx_flag;//基础数据变量,数据8、16、32,不能定义位bit
	unsigned char volatile Rx_flag;
    
    unsigned char *SendBuffer;//数据指针变量,数据集
    unsigned char *TranBuffer;

    void (*Send_Data)(unsigned char *);//函数指针变量,行为
    unsigned char (*Receve_Data)(void);
}UARTS_t;

extern UARTS_t idata UARTS;

3.源文件初始化

在#include“uarts.c”里面结构体初始化

#define UART1_REC_LENGTH 10
#define UART1_SEN_LENGTH 10

//static unsigned char tx_flag=0;//字符型、整型、浮点型
//static unsigned char rx_flag=0;

static unsigned char idata send_buf[UART1_SEN_LENGTH]={0};//数组
static unsigned char idata rece_buf[UART1_REC_LENGTH]={0};

static void send_data(unsigned char *);//函数
static unsigned char receve_data(void);

UARTS_t idata UARTS =
{
    0,//tx_flag,
    0,//rx_flag,

    send_buf,
    rece_buf,
    
	send_data,
	receve_data,
};

4.主函数引用

int main()
{
	if(UARTS.Tx_flag==1)//发送完成标志位
	{
		UARTS.Send_Data(UARTS.SendBuffer);
		UARTS.Tx_flag==0;//标志位清零
	}
	
	if(UARTS.Rx_flag==1)//接受完成标志位
	{
		*(UARTS.TranBuffer+i)=UARTS.Receve_Data();
		UARTS.Rx_flag==0;//标志位清零
	}

}

5.通过函数来访问数组

//下发数据
//通过结构体指针访问是通过参数->来访问数组
static void Control(UARTS_t* UARTS)
{
	UARTS_t const xdata COM=UARTS;//定义一个COM口结构体指针,把结构体名字UARTS赋给
	                   //COM口,COM口指向结构体指针了,靠COM口对应到数组的第几位了。
	*(COM->SendBuffer+9)=*(COM->SendBuffer+10);//地址+9是数组第几位,
	                                           //取星是数组第几位的值。
}

三、函数GPIO_init()初始化引用结构体

1.定义结构体。

将什么数值进行了赋值,赋给这些结构体变量?

typedef struct
{
	uint16_t GPIO_Pin;
	uint16_t GPIO_Speed;
	uint16_t GPIO_Mode;
}GPIO_InitTypeDef;//将什么数值进行了赋值,赋给这些结构体变量?

将枚举中的数值进行了赋值,赋给了结构体变量!

//本质都是具体的数值,但数值可读性不强。
#define GPIO_Pin_13 ((uint16_t)0X2000//将宏中的数值进行了赋值,赋给了结构体变量。

typedef enum
{
	GPIO_Mode_Out_OD = 0X14,
	GPIO_Mode_Out_PP = 0X10,
}GPIOMode_TypeDef;//将枚举中的数值进行了赋值,赋给了结构体变量。

typedef enum
{
	GPIO_Speed_10MHZ = 1,//0x01
	GPIO_Speed_20MHZ ,   //0x02
	GPIO_Speed_50MHZ ,   //0x03
}GPIOSpeed_TypeDef;//将枚举中的数值进行了赋值,赋给了结构体变量。

2.声明结构体

定义GPIO_InitStructure结构体变量,访问通过点(.)来访问。

GPIO_InitTypeDef GPIO_InitStructure;//定义GPIO_InitStructure结构体变量
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;//访问通过点(.)来访问
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHZ;//0x03
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//0x10
//这几句仅仅完成语言层面,完成了C语言的简单赋值
GPIO_Init(GPIOC,&GPIO_InitStructure);
//函数GPIO_init()才是将具体的参数写入到寄存器,完成了真正的初始化。

注意:前几句仅仅完成语言层面,完成了C语言的简单赋值!
WHZ

函数GPIO_init()才是将具体的参数写入到寄存器,完成了真正的初始化。

3.函数GPIO_init()初始化

//下发数据
//通过结构体指针访问是通过符号参数->来访问数据。

首先是函数GPIO_init(GPIO_TypeDef* GPIOx , GPIO_InitTypeDef* GPIO_InitStructure)的框架:
(1)定义一个GPIO_InitStructure结构体指针;
(2)把结构体名字GPIO_InitTypeDef赋给GPIO_InitStructure口;
(3)GPIO_InitStructure口指向结构体指针了,靠GPIO_InitStructure口对应到结构体成员变量了。
WHZ

其实GPIO_init()函数配置的就是:
(1)对应引脚的4个位;(引脚------》位(内存数据/中间变量(M0.0)));
(2)再将4个位写入到对应引脚的寄存器.(引脚-----》物理量寄存器(Q0.0));
(3)M0.0------->Q0.0(PLC程序框架里面的输出程序 if(M0.0==1)Q0.0=1).
王海洲
写函数的目的:能改变结构体成员变量的值

四、结构体变量和结构体指针变量

写函数的目的:能改变结构体成员变量的值

1.函数形参

值传递和址传递

值传递:
结构体变量的形式不可以改变结构体成员变量的值;
址传递:
结构体指针变量的形式可以改变结构体成员变量的值;

//写函数的目的:能改变结构体成员变量的值
//结构体变量
void GPIO_SetBits(GPIO_TypeDef GPIOx,uint16_t GPIO_Pin)
{
	GPIOx.BSRR |= GPIO_Pin;//点
}//错误,结构体变量的形式不可以改变结构体成员变量的值

//结构体指针变量
void GPIO_SetBits(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin)
{
	GPIOx->BSRR |= GPIO_Pin;//箭头
}//正确,结构体指针变量的形式可以改变结构体成员变量的值

2.定义结构体

这些结构体成员是我们自己定义的,单片机是不认得。
单片机只认识数值类型的地址。
(有名字,没地址)

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;//(有名字,没地址)

3.定义结构体指针变量

(GPIO_TypeDef*)GPIOC_BASE
(uint32*)0X40011000
这一句完美的将名字和地址结合起来了。
(有名字,也有地址,完美)

引用的时候要用箭头,指向CRH就是CRH,指向ODR就是ODR。
还是太长了,灵活的使用#define,替换成GPIOC就行了。

((GPIO_TypeDef*)GPIOC_BASE)->ODR//(有名字,也有地址,完美)
//或者
#define GPIOC (GPIO_TypeDef*)GPIOC_BASE//(有名字,也有地址,完美)
//通过结构体指针访问是通过符号参数->来访问数据
//上面5行这么多可以用下面2行表示,寄存器写法
GPIOC->CRH &=~(0X0F<<(4*5));
GPIOC->CRH |=~(1<<(4*5));

所以
声明结构体的时候尽量声明成:结构体指针变量。
或者
定义函数形参的时候尽量定义成:结构体指针变量。


总结

外设(ADC、UART、IIC)一般由标量、数组、函数组成,而结构体变量可以将外设封装。
但是
声明结构体的时候尽量声明成:结构体指针变量。
或者
定义函数形参的时候尽量定义成:结构体指针变量。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

分~耳

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值