乾貨|手把手教你寫單片機的結構體

摘要:你們想過沒有咱們用keil寫單片機的代碼,你的函數啊、變量啊最終都放在了哪裏?咱們一直說的內存五區,究竟是哪五區?到底放在芯片的那個地方呢?還有爲何你學完C語言指針和結構體32單片機裏面的關於結構體指針的內容仍是搞不清楚呢?若是你有這些問題,今天就帶你研究研究!程序員

這張圖學過STM32單片機的小夥伴應該都不陌生,咱們看到的STM32芯片已是已經封裝好的成品,主要由內核和片上外設組成。若與電腦類比,內核與外設就如同電腦上的CPU與主板、內存、顯卡、硬盤的關係。芯片和外設之間經過各類總線鏈接。鏈接被控總線的是FLASH,RAM和片上外設,這些功能部件共同排列在一個4GB的地址空間內。上面這些張圖是STM32F40XXX系列單片機的內存地址映射圖。數組

咱們的代碼就是放在Flash裏面(0x8000000~0x80FFFFF)。代碼就是你寫得各類函數,而在程序或者中聲明的各類變量都放在RAM中,局部變量就是在函數運行完空間就釋放了,全局變量就是程序運行完了再釋放,能夠這樣簡單的理解。markdown

CPU使用的變量是存儲在RAM裏面的,要問我RAM是啥,RAM就是個芯片。就是上圖的Block1的SRAM區。CPU是經過導線和RAM芯片鏈接的,而後能夠經過導線往RAM芯片裏面存儲數據和讀數據。首先RAM須要有個一開始的地址,對於STM32單片機來講開始地址是0x20000000,要問我爲啥要規定地址。只有規定了地址CPU纔好對數據進行存儲,要是沒有地址,瞎幾把存,瞎幾把取......函數

一、變量

1.定義了一個int型的變量,經過打印能夠看到這個變量存儲的地址是:0x20000000。這也證實了咱們內存的首地址是0x20000000。咱們定義的value變量就放在這裏。ui

2.再定義一個變量spa

經過打印能夠看到這個變量存儲的地址是:0x20000004。由於int類型在內存中佔據4個字節,因此第二個變量就存放在0x20000004這個地方。3d

綜上所述,定義的兩個變量在內存裏面是下面這樣子。指針

0x2000 0000地址裏面存儲的是 0 0x2000 0004地址裏面存儲的是 1code

二、指針變量

定義指針其實和定義變量同樣同樣的,只不過變量名前頭有個*orm

下面就定義了一個int型的指針變量,變量的名字是p。而後有人會問,爲啥變量名字前面加個*就是指針了?

答:搞C語言那幫傢伙們規定的。

定義指針和定義變量同樣哈,而後能夠定義各類類型的。

而後記住一句話:

指針這個變量是存變量的地址的!

指針這個變量是存變量的地址的! 指針這個變量是存變量的地址的!

因此給指針賦值天然是把變量的地址給它。

#include "sys.h"
#include "led.h"
#include "delay.h"
#include "usart.h"

int value = 0;
int value2 = 1;
int *p;

int main(void) {	
	uart_init(115200);
	delay_init();
	p=&value;//把變量value的地址複製給這個指針
	printf("Address of a: %p\n",p);//打印下這個指針指向的地址
  while(1)
	{	
	}	
}
複製代碼

通常什麼類型的指針變量就應該賦值什麼類型變量的地址。如再定義個char型

#include "sys.h"
#include "led.h"
#include "delay.h"
#include "usart.h"

int value = 0;
int value2 = 1;
int *p;//定義一個指針

char value3=1;
char *q;
	
int main(void) {	
	uart_init(115200);//串口初始化
	delay_init();
	
	p=&value;//把變量value的地址複製給這個指針
	q=&value3;//把變量value的地址複製給這個指針
	
	printf("Address of a: %p\n",q);//打印下這個指針指向的地址
    while(1)
	{	
	}	
}
複製代碼

那些規定C語言的大佬弄出來指針這個玩意有啥用?

三、指針有啥用?

1.咱先使用感覺下指針,而後具體有啥用就本身體會了。前面咱把一個變量的地址賦值給了指針了,而後搞C語言的那幫傢伙們又規定。*{指針變量名} :表明了這個指針所指向的變量。

啥意思呢?

對照下面的程序 p=&value, p記錄的就是變量value的地址, 而後*p就表明value。

#include "sys.h"
#include "led.h"
#include "delay.h"
#include "usart.h"

int value = 0;
int *p;//定義一個指針
	
int main(void) {	
	uart_init(115200);//串口初始化
	delay_init();
	
	p=&value;//把變量value的地址複製給指針變量p
	
	printf("Address of a: %d\n",value);
	printf("Address of b: %d\n",*p);
  while(1)
	{	
	}	
}
複製代碼

有人會想......就這?

這不是脫了褲子放屁

畫蛇添足?

其實我一開始也是這樣想的......

既然 * p就表明value 那麼 * p=XXXX,不就是至關於value=XXXX

看看下面這個例子

#include "sys.h"
#include "led.h"
#include "delay.h"
#include "usart.h"
int value = 0;
int *p;//定義一個指針 
int main(void) {	
	uart_init(115200);//串口初始化
	delay_init();
	
	p=&value;//把變量value的地址複製給指針變量p
	printf("value of a: %d\n",value);
	
	*p=520;	
	
	printf("value of b: %d\n",value);
    while(1)
	{	
	}	
}

複製代碼

仍是沒感受到指針有啥用?彆着急,先把基本的知識點學完哈。沒有最基本的知識儲備是不能夠的,由於厚積而薄發!

見過返回值是指針的函數沒?

四、函數指針

先看一下,若是感受不理解就接着往下看

#include "sys.h"
#include "led.h"
#include "delay.h"
#include "usart.h"

int value = 0;
int *p;//定義一個指針
	
int *function(void) {
   return &value;//把value的地址返回
}
	
int main(void) {	
	uart_init(115200);//串口初始化
	delay_init();
	
	p=function();//調用函數,其實就是把value的地址賦值給了p
	
	printf("Address1 of a: %p\n",&value);//打印value的地址
	printf("Address2 of a: %p\n",p);//打印p所表明的地址
	
    while(1)
	{	
	}	
}
複製代碼

不少人用過返回值是int、char 等等的函數,可是在int,char 後面加個*

估計對於初學者沒有用過。看下面的,其實就是指針之間賦值。下面就是把p(int*類型的指針) 表明的地址賦值給q

變量之間能夠互相賦值吧,指針之間也同樣,能夠互相之間賦值。

其實和上面是同樣的道理,那個函數function返回值是一個int*類型的指針,而後賦值給了p而已

#include "sys.h"
#include "led.h"
#include "delay.h"
#include "usart.h"

int value = 0;
int *p;//定義一個指針
int *q;//定義一個指針
	
int main(void) {	
	uart_init(115200);//串口初始化
	delay_init();
	
	p=&value;//把value的地址賦值給了p 
	q=p;//把p表明的地址給q
	
	printf("Address1 of a: %p\n",&value);//打印value的地址
	printf("Address2 of a: %p\n",q);//打印p所表明的地址
	
  while(1)
	{	
	}	
}
複製代碼

姑且再問一句,函數名字是啥?

我們都知道這樣調用函數

#include "sys.h"
#include "led.h"
#include "delay.h"
#include "usart.h"

void function() {
  printf("zhiguoxin\n");
}
int main(void) {	
	uart_init(115200);//串口初始化
	delay_init();	
	
  function();	
    
  while(1)
	{	
	}	
}
複製代碼

可是這樣的見過沒

#include "sys.h"
#include "led.h"
#include "delay.h"
#include "usart.h"

void (*fun)();

void function() {
  printf("zhiguoxin\n");
}

int main(void) {	
	uart_init(115200);//串口初始化
	delay_init();
	
	fun = function;
  fun();
		
  while(1)
	{	
	}	
}
複製代碼

這裏採用了函數指針

先記住一句話

函數名就是這個函數的地址!

函數名就是這個函數的地址! 函數名就是這個函數的地址!

既然是地址,那麼這個地址應該能夠賦值給一個指針。由於是函數的地址,因此咱定義的指針也必定是一個函數類型的。

上面的函數void function()是一個沒有返回值,沒有形參的函數。那麼咱須要定義一個這種的指針類型,其實就是void (*指針變量名字,隨意寫) ()。上面寫的是 void (*fun)(); fun就是一個函數類型的指針,是一個沒有返回值,沒有形參的函數指針。

咱能夠把這種函數賦值給這個指針變量。就是上面的fun=function。那麼這個函數指針便表明了那個函數fun就等同於function。因此調用 fun(); 就等同於調用function()。

若是函數有形參怎麼辦? 好辦,它有咱就加

#include "sys.h"
#include "led.h"
#include "delay.h"
#include "usart.h"

void (*fun)(int a);

void function(int value) {
  printf("value= %d\r\n",value);
}

int main(void) {	
	uart_init(115200);//串口初始化
	delay_init();
	
	fun = function;//把function賦值給fun
  fun(520);//fun就等同於function
		
  while(1)
	{	
	}	
}
複製代碼

若是函數有返回值怎麼辦?照加不誤

#include "sys.h"
#include "led.h"
#include "delay.h"
#include "usart.h"

int res;

int (*fun)(int a);

int function(int value) {
  return value;
}
int main(void) {	
	uart_init(115200);//串口初始化
	delay_init();
	
	fun = function;//把function賦值給fun
  res = fun(520);//fun就等同於function
		
	printf("res = %d",res);
  while(1)
	{	
	}	
}
複製代碼

小總結一下

指針呢其實基本的也就是上面那些,指針就是用來記錄變量的地址的。或是作地址之間的傳遞的。

&表明取地址符。

*表明取數據。 &{變量名} :就是把這個變量的地址取出來。 *{指針變量名} :就是把這個指針所表明的地址裏面的存的值取出來

下面看一些比較常見的應用。把數組的地址賦值給指針,而後用指針操做數組

#include "sys.h"
#include "led.h"
#include "delay.h"
#include "usart.h"

char temp[3]={1,2,3};
char *p;

int main(void) {	
	uart_init(115200);//串口初始化
	delay_init();
	
  p=temp;//將數組名賦值給指針變量p,p就指向數組temp的首地址
		
	printf("value0 = %d\r\n",*p);    //p就表明數組的第一個數據的地址
	printf("value1 = %d\r\n",*(p+1));//p+1就表明數組的第二個數據的地址
	printf("value2 = %d\r\n",*(p+2));//p+2就表明數組的第三個數據的地址
	
	printf("temp[0] = %d\r\n",p[0]);//p[0]等同於temp[0]
	printf("temp[1] = %d\r\n",p[1]);//p[1]等同於temp[1]
	printf("temp[2] = %d\r\n",p[2]);//p[2]等同於temp[2] 
  while(1)
	{	
	}	
}
複製代碼

五、函數的形參是一個指針

#include "sys.h"
#include "led.h"
#include "delay.h"
#include "usart.h"

char temp[3]={1,2,3};

void function(char *value) {
	printf("value0 = %d\r\n",value[0]);
	printf("value1 = %d\r\n",value[1]);
	printf("value2 = %d\r\n",value[2]);
}
int main(void) {	
	uart_init(115200);//串口初始化
	delay_init();
	
	function(temp);

  while(1)
	{	
	}	
}
複製代碼

以上的指針的基本知識多練習幾遍就能夠。指針真正的應用是在於代碼的封裝。可能對於初學者感覺不到其做用,可是當你成爲真正的開發人員。你會發現把好多功能函數封裝起來,而後留出接口來調用是之後必不可少的。

封裝的時候會大量的使用指針,函數指針、結構體指針等,怎麼說呢!90%的程序員敲的是字母,寫的是代碼。當你開始封裝的時候,你寫的即是思想,可是須要必定的基礎知識儲備才能達到。

默認標題_橫版二維碼_2021-05-29-0.png

相關文章
相關標籤/搜索