第二章 单片机中c的基础知识

第二章 单片机中c的基础知识



前言

单片机入门之前,c语言的学习也越来越重要,当然我们可以在学习单片机的过程中,慢慢的完善c语言的知识,本文就绍了单片机学习需要c语言的基础知识。
了解位、字节、字的关系。
加强认识和理解栈的使用过程是RTOS多任务的核心,堆比栈较简单。
本文档参考韦东山老师课程讲解。


一、语法基础资料

https://book.douban.com/subject/4279678/

位置

https://www.dedao.cn/ebook/reader?id=L5BbmPyQPrjybo2eO1GvAmNJnlYxV0RK69W8XDBK9qZpgkRELd75z4Ma6oDRrqjY

二、基础知识

1.预处理

#include<stdio.h>

#define GPIOC (GPIO_RegistStruct*)GPIOBase0400010001 

#if
...
#elseif
...
#else
...
#endif

2.数据存储

static
extern
const
volatile

3.数据结构

struct
enum
union
typedef

4.数据类型

char
short
int
long
signed
unsigned
float
double
sizeof

5.运算和控制

=
+
-
*
while
do-while
if-else
switch-case
continue
break
return

6.位操作和逻辑运算

<<
>>
&
|
~
^

三、位、字节、字的关系

1.位(bit)

计算机中最基本的单位, 取值0或1

2.字节(Byte)

计算机中数据存储的基本单位, 8位=1字节

3.字(Word)

计算机进行数据处理和运算的单位,
32位机中,4字节=1字;
64位机中,8字节=1字;

四、栈和堆

1.堆

堆比栈较简单
堆就是一块空闲的内存,你可以管理内存,从这一块内存中来取出一部分,用完后再释放回去,

比如:定义char buff[1024],他就是一块空闲的内存,只要在它上面实现内存的分配和释放,该数组就是一个堆。

我们来实现一个简单的函数

char buff[1024]//1.先在buff中分配一小块内存,下标就是从0到1023
char * buf_pos=0;//2.定义一个buf_pos=0,让这个首位置返回去
                //使用一个整数buf_pos=0表示一块空闲内存的位置

void *malloc(int size)//分配size大小的空间
{
	int old_pos=buf_pos;//5.使用一个整数old_pos表示一块空闲内存的位置
	buf_pos+=size;//4.让这个buf_pos等于原来的位置加上这个size
	return &buff[old_pos];//3.返回buf_pos这个位置的地址,然后还要调整一下这个地址
}

Malloc函数比较简单,就是先在buff中分配一小块内存,下标就是从0到1023。
如果我们想分配size大小的空间,怎么分配呢?
定义一个pos=0,让这个首位置返回去,然后让这个pos等于原来的位置加上这个size,
当我们在这块空闲的buff内存上实现malloc时,这块内存成为堆。

void free(void*buff)//假装我们在buff实现了free
{
    /*err8/
}

使用一个整数pos表示一块空闲内存的位置。
使用这种最简单的方法不能实现free函数,如果要释放掉你分配掉的那块内存,假装我们在buff实现了free,就可以在主函数中使用了。

int main()
{
	int i;
	char *buf=my_malloc(100);//然后在里面添加内容,先定义一个i
	for(i=0;i<26;i++)
	{
		buf[i]=’A’+i;
	}
}

然后使用debug模拟器仿真一下,数组buff[]里面是否存入数据。
如果使用中文目录退出debug时会报错。

2.栈

栈是RTOS的基础,离开栈是不行的,每个任务他都要有自己的栈,互相独立。

栈的使用过程是RTOS多任务的核心,在后面创建任务时你会发现,你要创建一个任务,你必须给这个任务单独分配栈。

栈的作用:
栈是一个幕后英雄,在我们编写程序的时候感觉不到栈的存在。

我们写一个简单程序,让main函数调用a_test(),a_test()中定义一个vale值,a_test()再调用b_test()和c_test()。

void c_test()
{
}
void b_test()
{
}
void a_test()
{
	int num=5,vale;
	num=num+vale;
	b_test();
	c_test();
}
int main()
{
	a_test();
	return 0;
}

在这个过程中没有感觉到栈的存在,但是我来问几个问题,

第一个问题:从C语言中可以直接看到返回到哪里,但是返回地址保存在哪里?

比如main函数他怎么调用a_test()函数,我得记录下a_test()的返回地址。

第一步:他把返回地址保存在某个寄存器里面,LR(link register)讲ARM架构时会讲到这个寄存器的,可以保存一些值,main函数调用a_test()函数之前,他会把a_test()函数下一句要执行的语句保存,LR=a_test()函数执行完后下一语句的地址,return 0;

第二步:然后干嘛呢?然后调用a_test()函数。

同理,a_test()函数调用b_test()函数时,他也是一样的,做同样的事情,先保存b_test()函数下一句要执行的语句返回地址值保存,LR=b函数执行完后下一语句的返回地址,然后调用b函数。

那么问题就来了,a_test()函数执行完后下一语句的地址保存到LR里面,b_test()函数执行完后下一语句的地址也保存到LR里面,LR被覆盖?

如果你不做处理的话,LR肯定被覆盖,那怎么处理呢?简单。

在a_test()函数内部,他要把LR的值保存起来,把LR存入栈中,后面调用b_test()函数时,LR就不怕被覆盖掉了,函数b他也会在函数b_test()内部也把返回值保存到栈中。

你看,第一个问题不就解决了,返回位置保存到每个任务自己的栈中。

什么是栈,栈就是一块空闲的内存,比如打开汇编代码,他在执行main函数之前,他要使用汇编代码设置这个栈,SP就是栈寄存器,让他指向一块空闲的内存,然后就可以调用c函数了。

第二个问题:整个使用栈的过程是怎么样的呢?

根据C函数开头知道:
1、先划分栈,(划分出来的栈用来保存LR等寄存器,还有局部变量)
2、显然LR等寄存器存入栈
3、执行代码。比如num=5的话,不是刚刚给num分配了栈空间了吗?把8这个值写到那个栈空间里面去。

BL main会把下一条指令地址保存到LR里面,所以说BL main他会做两件事情,

第一件LR=返回地址,第二件然后执行main函数

,main函数会做什么事情呢?
main函数他会划分出自己的栈空间,SP=SP-N,这N字节的内存就是main函数自己的栈(main’s stack),在里面会保存什么呢?
会保存LR等寄存器,还会保存局部变量。

a_test()\b_test()函数与主函数类似,从这个过程中可以发现,栈在保存LR返回地址时是怎么起作用的。栈对局部变量起作用也是分配局部变量空间,在运行到赋值指令时,让局部内存的值变为5,在运行到局部变量加vale的时候,他就让5+vale.

总结

了解位、字节、字的关系,加强认识和理解栈的使用过程是RTOS多任务的核心,堆比栈较简单。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

分~耳

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

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

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

打赏作者

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

抵扣说明:

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

余额充值