標(biāo)題: 單片機(jī)C語言定義一個(gè)變量,如果不賦值,難道不是默認(rèn)等于0嘛 [打印本頁]

作者: 鄭常椿    時(shí)間: 2023-2-9 20:40
標(biāo)題: 單片機(jī)C語言定義一個(gè)變量,如果不賦值,難道不是默認(rèn)等于0嘛

今天測試了一下按鍵控制蜂鳴器,具體程序見附件
想要實(shí)現(xiàn)按鍵按下,蜂鳴器響,按鍵按下,蜂鳴器關(guān)的功能
這個(gè)按道理很簡單,可是實(shí)際操作時(shí)發(fā)現(xiàn)了程序里一個(gè)奇怪現(xiàn)象。!
按鍵檢測使用的是GPIO上拉輸入模式,也就是空懸為高電平
這樣按下按鍵之后檢測到低電平剛好合適
按鍵一端接gnd,一端接PB0,PB11這里未使用
蜂鳴器是買的低電平驅(qū)動(dòng)的小模塊,3V到5V都兼容,這里只用到了PA1,PA2未使用
具體程序如下
這是蜂鳴器的初始化和翻轉(zhuǎn)單片機(jī)程序
/********************************
#include"stm32f10x.h"                 // Device header

voidLED_Init(void) //也可用蜂鳴器低電平驅(qū)動(dòng)代替
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitTypeDefGPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode= GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin= GPIO_Pin_1 | GPIO_Pin_2;
GPIO_InitStructure.GPIO_Speed= GPIO_Speed_50MHz;

GPIO_Init(GPIOA,&GPIO_InitStructure);
GPIO_SetBits(GPIOA,GPIO_Pin_1 | GPIO_Pin_2);//初始設(shè)置高,防止開始低電平驅(qū)動(dòng)蜂鳴器
}
void LED1_Turn(void) //蜂鳴器狀態(tài)翻轉(zhuǎn)程序
{
if(GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_1)==1)
{
GPIO_ResetBits(GPIOA,GPIO_Pin_1);
}
elseif(GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_1)==0)
{
GPIO_SetBits(GPIOA,GPIO_Pin_1);
}
}
*********************************************/
這是按鍵的相關(guān)程序
/*****************************************
#include"stm32f10x.h"                 // Device header
#include"Delay.h"
void Key_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
GPIO_InitTypeDefGPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//上拉輸入,懸空時(shí)為高電平,適合按鍵
GPIO_InitStructure.GPIO_Pin= GPIO_Pin_1 | GPIO_Pin_11;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//只對(duì)輸出管用,這里輸入隨便填

GPIO_Init(GPIOB,&GPIO_InitStructure);
GPIO_SetBits(GPIOB,GPIO_Pin_1 | GPIO_Pin_11);//初始設(shè)置高,防止低電平驅(qū)動(dòng)蜂鳴器
}

uint8_tGet_KeyNum(void)
{
uint8_t KeyNum = 0;//定義一個(gè)局部變量未檢測為0,一定要加=0!!
if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1)== 0)
{
Delay_ms(20);//按下消抖
while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1) ==0);  //沒有松手一直執(zhí)行這條
Delay_ms(20);//松開消抖
KeyNum= 1;
}        
if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_11)== 0)
{
Delay_ms(20);//按下消抖
while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_11) ==0);  //沒有松手一直執(zhí)行這條,用來確認(rèn)松手
Delay_ms(20);//松開消抖
KeyNum= 11;
}
returnKeyNum;
}
**********************************************/
以下是main.c內(nèi)的所有調(diào)用函數(shù)
/********************************************
#include"stm32f10x.h"                 // Device header
#include"Delay.h"
#include"LED.h"
#include"Key.h"

#define di 100


int main(void)
{
uint8_t KeyNum; //main函數(shù)內(nèi)局部變量
LED_Init();
Key_Init();

while(1)
{
KeyNum= Get_KeyNum();

if(KeyNum==1) //PB1按鍵按下
{
LED1_Turn();//PA1翻轉(zhuǎn)

}

}
}
*********************************************/
以上看上去確實(shí)沒有問題對(duì)吧,實(shí)際上也沒有問題,
因?yàn)檫@是我發(fā)現(xiàn)問題之后,修正過的程序
真正的問題在于,
原來的程序里只有一條語句與這不一樣,
那就是按鍵的相關(guān)程序里面的
uint8_tGet_KeyNum(void)函數(shù)里的

第一行的uint8_tKeyNum = 0;  這樣寫達(dá)到了我的目的:按鍵按下,蜂鳴器響,按鍵按下,蜂鳴器關(guān)

原先我寫的是uint8_t KeyNum;這樣執(zhí)行只有按著按鍵的時(shí)候蜂鳴器才會(huì)響???非常奇怪的現(xiàn)象

在我學(xué)習(xí)51單片機(jī)的過程中,老師一直對(duì)我說的是,如果定義一個(gè)變量,不給它賦初值,默認(rèn)為0。
現(xiàn)在看起來好像是我理解有問題。。。。
uint8_tKeyNum = 0;和uint8_t KeyNum;有啥區(qū)別???
如果沒有區(qū)別,為什么現(xiàn)象不一樣???
局部變量里面定義了之后,
如果不賦值
Return 返回的難道不是0???是個(gè)隨記數(shù)??也不對(duì)啊,求賜教?
不能理解,所以想請教各位大佬,如覺幼稚,請多多指教。

3-3按鍵控制LED.7z

174.89 KB, 下載次數(shù): 3


作者: Hephaestus    時(shí)間: 2023-2-10 00:14
全局變量默認(rèn)才是0,如果你老師沒講錯(cuò),那就是你記錯(cuò)了。

建議你看看《數(shù)據(jù)結(jié)構(gòu)》這本書,遞歸那一章很好的說明了c語言局部變量是從哪里來的,如果你看懂了的話,就很容易知道為什么不是0。

另外,MDK是符合c語言標(biāo)準(zhǔn)的,C51不符合c語言標(biāo)準(zhǔn),《數(shù)據(jù)結(jié)構(gòu)》對(duì)局部變量的描寫符合MDK,不符合C51。
作者: 13423265909    時(shí)間: 2023-2-10 02:13
不確定。 但一般情況是,靜態(tài)變量(static)與全局變量都默認(rèn)為0,局部變量值不確定(很多情況下不為0)。
作者: wulin    時(shí)間: 2023-2-10 06:27
全局變量是個(gè)人專用衛(wèi)生間,用后離開到下次再用內(nèi)部環(huán)境不變。局部變量是公共衛(wèi)生間,用后離開到下次再用內(nèi)部環(huán)境不確定?赡芫砑埑榭樟,馬桶還沒沖。所以局部變量一定要先賦值再使用,函數(shù)退出時(shí),將釋放其空間。
作者: yxtao    時(shí)間: 2023-2-10 09:04
通常情況下定義變量緊跟著就給賦個(gè)初值,就是為了防止函數(shù)每次調(diào)用時(shí)局部變量值的不確定

作者: glinfei    時(shí)間: 2023-2-10 10:26
要看編譯器的處理方式,不過只有靜態(tài)變量才可能初始化為0,局部變量是動(dòng)態(tài)的,就是隨機(jī)數(shù)了。
作者: aayon1979    時(shí)間: 2023-2-10 11:28
定義變量后及時(shí)賦個(gè)初始值是個(gè)好的習(xí)慣

作者: matlab?    時(shí)間: 2023-2-10 11:29
最近剛好遇到這個(gè)問題,把局部轉(zhuǎn)成靜態(tài)變量就好了

作者: 鄭常椿    時(shí)間: 2023-2-10 11:54
Hephaestus 發(fā)表于 2023-2-10 00:14
全局變量默認(rèn)才是0,如果你老師沒講錯(cuò),那就是你記錯(cuò)了。

建議你看看《數(shù)據(jù)結(jié)構(gòu)》這本書,遞歸那一章很 ...

感謝大佬,學(xué)校安排的只有c語言程序設(shè)計(jì),還是大一學(xué)的,現(xiàn)在看來還是學(xué)的太淺了
我會(huì)去學(xué)學(xué)數(shù)據(jù)結(jié)構(gòu)的,這本書聽說過,趕緊整一本回去惡補(bǔ)
作者: fishafish    時(shí)間: 2023-2-10 13:40
鄭常椿 發(fā)表于 2023-2-10 11:54
感謝大佬,學(xué)校安排的只有c語言程序設(shè)計(jì),還是大一學(xué)的,現(xiàn)在看來還是學(xué)的太淺了
我會(huì)去學(xué)學(xué)數(shù)據(jù)結(jié)構(gòu)的 ...

我單片機(jī)C編程搞得不錯(cuò),但是從來不看什么數(shù)據(jù)結(jié)構(gòu),如何?
作者: Hephaestus    時(shí)間: 2023-2-10 16:58
c編程搞得不錯(cuò)有兩種,一種是真的不錯(cuò),另一種是井蛙級(jí)搞得不錯(cuò),樓上顯然是后一種。
作者: Hephaestus    時(shí)間: 2023-2-10 20:47
補(bǔ)充一下,如果樓主搞過Windows編程,會(huì)遇到著名的“手持兩把錕斤拷,口中疾呼燙燙燙”的問題,此問題的根源就是初始化以后的堆棧里面并不是0。
作者: coody_sz    時(shí)間: 2023-2-10 22:01
不一定,所以一定要養(yǎng)成清內(nèi)存或給變量初值的習(xí)慣。
作者: wufa1986    時(shí)間: 2023-2-13 14:18
當(dāng)然不是,RAM上是隨機(jī)值,很多單片機(jī),包括51單片機(jī),STM32單片機(jī)等進(jìn)入mian前還有一段代碼初始化
作者: jizhongbiao    時(shí)間: 2023-2-13 18:00
局部變量是定義在棧上的,如果不加static修飾在退出函數(shù)后會(huì)釋放該空間。所以這個(gè)變量每次進(jìn)入函數(shù)都是不同的地址,所以如果這個(gè)地址剛好被某個(gè)函數(shù)使用過那么初始值就不是0.
作者: jizhongbiao    時(shí)間: 2023-2-13 18:03
鄭常椿 發(fā)表于 2023-2-10 11:54
感謝大佬,學(xué)校安排的只有c語言程序設(shè)計(jì),還是大一學(xué)的,現(xiàn)在看來還是學(xué)的太淺了
我會(huì)去學(xué)學(xué)數(shù)據(jù)結(jié)構(gòu)的 ...

這不是數(shù)據(jù)結(jié)構(gòu)的內(nèi)容,是鏈接和作用域的內(nèi)容。看一遍c primer plus后把基礎(chǔ)搞清楚再看數(shù)據(jù)結(jié)構(gòu)吧。尤其是指針要搞透徹。
作者: Hephaestus    時(shí)間: 2023-2-15 17:10
對(duì)于標(biāo)準(zhǔn)c語言來說,局部變量是在堆棧之上,跟鏈接和作用域沒有一毛錢關(guān)系,局部變量是怎么來的,又是怎么沒的,只有《數(shù)據(jù)結(jié)構(gòu)》里面遞歸一節(jié)說的最清楚。

對(duì)于不遵守標(biāo)準(zhǔn)的野路子編譯器,比如Keil C51才跟鏈接有關(guān)。
作者: jizhongbiao    時(shí)間: 2023-2-16 17:57
Hephaestus 發(fā)表于 2023-2-15 17:10
對(duì)于標(biāo)準(zhǔn)c語言來說,局部變量是在堆棧之上,跟鏈接和作用域沒有一毛錢關(guān)系,局部變量是怎么來的,又是怎么 ...

你確定你學(xué)過C語言?數(shù)據(jù)結(jié)構(gòu)怎么和c語言綁定了搞不懂。。。
作者: Hephaestus    時(shí)間: 2023-2-16 19:11
jizhongbiao 發(fā)表于 2023-2-16 17:57
你確定你學(xué)過C語言?數(shù)據(jù)結(jié)構(gòu)怎么和c語言綁定了搞不懂。。。

c語言教科書一般不會(huì)告訴你局部變量是怎么來的,又是怎么沒的,《數(shù)據(jù)結(jié)構(gòu)》會(huì)講。

你說一本講局部變量來歷的教科書好了。
作者: glinfei    時(shí)間: 2023-2-16 23:24
Hephaestus 發(fā)表于 2023-2-16 19:11
c語言教科書一般不會(huì)告訴你局部變量是怎么來的,又是怎么沒的,《數(shù)據(jù)結(jié)構(gòu)》會(huì)講。

你說一本講局部變 ...

學(xué)沒學(xué)過數(shù)據(jù)結(jié)構(gòu)是程序員的一個(gè)分水嶺,你沒法跟沒學(xué)過數(shù)據(jù)結(jié)構(gòu)的人講清楚原因的,但可以出個(gè)題,比如如何寫個(gè)走迷宮程序
作者: xxxevery    時(shí)間: 2023-2-17 09:28
養(yǎng)成良好的編程習(xí)慣是對(duì)的,否則會(huì)經(jīng)常出現(xiàn)一些讓人頭疼的小問題
作者: Hephaestus    時(shí)間: 2023-2-17 19:30
glinfei 發(fā)表于 2023-2-16 23:24
學(xué)沒學(xué)過數(shù)據(jù)結(jié)構(gòu)是程序員的一個(gè)分水嶺,你沒法跟沒學(xué)過數(shù)據(jù)結(jié)構(gòu)的人講清楚原因的,但可以出個(gè)題,比如如 ...

夏蟲不可語冰,井蛙不可語海。
作者: pdwdzz    時(shí)間: 2023-2-17 21:58
定義變量隨手賦值是好習(xí)慣,很多低端單片機(jī),是不處理內(nèi)存初始狀態(tài)的。
作者: xinxin2001853    時(shí)間: 2023-2-20 17:36
單片機(jī)C語言變量默認(rèn)值有可能不為0,是隨機(jī)數(shù),給編譯器有關(guān)。
作者: jizhongbiao    時(shí)間: 2023-2-21 18:01
Hephaestus 發(fā)表于 2023-2-16 19:11
c語言教科書一般不會(huì)告訴你局部變量是怎么來的,又是怎么沒的,《數(shù)據(jù)結(jié)構(gòu)》會(huì)講。

你說一本講局部變 ...

所有的教科書都會(huì)講啊
作者: jizhongbiao    時(shí)間: 2023-2-21 18:03
Hephaestus 發(fā)表于 2023-2-15 17:10
對(duì)于標(biāo)準(zhǔn)c語言來說,局部變量是在堆棧之上,跟鏈接和作用域沒有一毛錢關(guān)系,局部變量是怎么來的,又是怎么 ...

你所謂的遞歸講了是恰好因?yàn)檫f歸使用了棧,棧是作用域的內(nèi)容啊。。。算了這論壇水平是在是有限。
作者: jizhongbiao    時(shí)間: 2023-2-21 18:04
glinfei 發(fā)表于 2023-2-16 23:24
學(xué)沒學(xué)過數(shù)據(jù)結(jié)構(gòu)是程序員的一個(gè)分水嶺,你沒法跟沒學(xué)過數(shù)據(jù)結(jié)構(gòu)的人講清楚原因的,但可以出個(gè)題,比如如 ...

沒學(xué)過數(shù)據(jù)結(jié)構(gòu)的能叫程序員?還寫個(gè)迷宮哈哈哈大一的?




歡迎光臨 (http://www.torrancerestoration.com/bbs/) Powered by Discuz! X3.1