一、使用proteus繪制簡單的電路圖,用于后續仿真
二、編寫程序
/********************************************************************************************************************
---- @Project: Pointer
---- @File: main.c
---- @Edit: ZHQ
---- @Version: V1.0
---- @CreationTime: 20200809
---- @ModifiedTime: 20200809
---- @Description:
---- 波特率是:9600 。
---- 通訊協議:EB 00 55 XX YY
---- 把5個隨機數據按從大到小排序,用冒泡法來排序。
---- 通過電腦串口調試助手,往單片機發送EB 00 55 08 06 09 05 07 指令,其中EB 00 55是數據頭,08 06 09 05 07 是參與排序的5個隨機原始數據。單片機收到指令后就會返回13個數據,最前面5個數據是第1種方法的排序結果,中間3個數據EE EE EE是第1種和第2種的分割線,為了方便觀察,沒實際意義。最后5個數據是第2種方法的排序結果.
----
---- 比如電腦發送:EB 00 55 08 06 09 05 07
---- 單片機就返回:09 08 07 06 05 EE EE EE 09 08 07 06 05
---- 單片機:AT89C52
********************************************************************************************************************/
#include "reg52.h"
/*——————宏定義——————*/
#define FOSC 11059200L
#define BAUD 9600
#define T1MS (65536-FOSC/12/500) /*0.5ms timer calculation method in 12Tmode*/
#define const_array_size 5 /* 參與排序的數組大小 */
#define const_voice_short 19 /*蜂鳴器短叫的持續時間*/
#define const_rc_size 10 /*接收串口中斷數據的緩沖區數組大小*/
#define const_receive_time 5 /*如果超過這個時間沒有串口數據過來,就認為一串數據已經全部接收完,這個時間根據實際情況來調整大小*/
/*——————變量函數定義及聲明——————*/
/*蜂鳴器的驅動IO口*/
sbit BEEP = P2^7;
/*LED*/
sbit LED = P3^5;
unsigned int uiSendCnt = 0; /*用來識別串口是否接收完一串數據的計時器*/
unsigned char ucSendLock = 1; /*串口服務程序的自鎖變量,每次接收完一串數據只處理一次*/
unsigned int uiRcregTotal = 0; /*代表當前緩沖區已經接收了多少個數據*/
unsigned char ucRcregBuf[const_rc_size]; /*接收串口中斷數據的緩沖區數組*/
unsigned int uiRcMoveIndex = 0; /*用來解析數據協議的中間變量*/
unsigned int uiVoiceCnt = 0; /*蜂鳴器鳴叫的持續時間計數器*/
unsigned char ucUsartBuffer[const_array_size]; /* 從串口接收到的需要排序的原始數據 */
unsigned char ucGlobalBuffer_3[const_array_size]; /* 第3種方法,參與具體排序算法的全局變量數組 */
unsigned char ucGlobalBuffer_4[const_array_size]; /* 第4種方法,用來接收輸出接口數據的全局變量數組 */
/**
* @brief 定時器0初始化函數
* @param 無
* @retval 初始化T0
**/
void Init_T0(void)
{
TMOD = 0x01; /*set timer0 as mode1 (16-bit)*/
TL0 = T1MS; /*initial timer0 low byte*/
TH0 = T1MS >> 8; /*initial timer0 high byte*/
}
/**
* @brief 串口初始化函數
* @param 無
* @retval 初始化T0
**/
void Init_USART(void)
{
SCON = 0x50;
TMOD = 0x21;
TH1=TL1=-(FOSC/12/32/BAUD);
}
/**
* @brief 外圍初始化函數
* @param 無
* @retval 初始化外圍
* 讓數碼管顯示的內容轉移到以下幾個變量接口上,方便以后編寫更上一層的窗口程序。
* 只要更改以下對應變量的內容,就可以顯示你想顯示的數字。
**/
void Init_Peripheral(void)
{
ET0 = 1;/*允許定時中斷*/
TR0 = 1;/*啟動定時中斷*/
TR1 = 1;
ES = 1; /*允許串口中斷*/
EA = 1;/*開總中斷*/
}
/**
* @brief 初始化函數
* @param 無
* @retval 初始化單片機
**/
void Init(void)
{
LED = 0;
Init_T0();
Init_USART();
}
/**
* @brief 延時函數
* @param 無
* @retval 無
**/
void Delay_Long(unsigned int uiDelayLong)
{
unsigned int i;
unsigned int j;
for(i=0;i for(j=0;j<500;j++) /*內嵌循環的空指令數量*/ { ; /*一個分號相當于執行一條空語句*/ } } } /** * @brief 延時函數 * @param 無 * @retval 無 **/ void Delay_Short(unsigned int uiDelayShort) { unsigned int i; for(i=0;i ; /*一個分號相當于執行一條空語句*/ } } /** * @brief 串口發送函數 * @param unsigned char ucSendData * @retval 往上位機發送一個字節的函數 **/ void eusart_send(unsigned char ucSendData) { ES = 0; /* 關串口中斷 */ TI = 0; /* 清零串口發送完成中斷請求標志 */ SBUF = ucSendData; /* 發送一個字節 */ Delay_Short(400); /* 每個字節之間的延時,這里非常關鍵,也是最容易出錯的地方。延時的大小請根據實際項目來調整 */ TI = 0; /* 清零串口發送完成中斷請求標志 */ ES = 1; /* 允許串口中斷 */ } /** * @brief 第3種方法 * @param p_ucInputBuffer p_ucOutputBuffer * @retval * 第3種方法,為了改進第2種方法的用戶體驗,用指針為函數多增加一個數組輸出接口。 * 這樣,函數的數組既有輸入接口,又有輸出接口,已經堪稱完美了。 * 本程序中*p_ucInputBuffer輸入接口,*p_ucOutputBuffer是輸出接口。 **/ void big_to_small_sort_3(unsigned char *p_ucInputBuffer, unsigned char *p_ucOutputBuffer) { unsigned char i; unsigned char k; unsigned char ucTemp; /* 在兩兩交換數據的過程中,用于臨時存放交換的某個變量 */ unsigned char ucBuffer_3[const_array_size]; /* 第3種方法,參與具體排序算法的局部變量數組 */ for(i = 0; i < const_array_size; i ++) /* 參與排序算法之前,先把輸入接口的數據全部搬移到局部變量數組中。 */ { ucBuffer_3[i] = p_ucInputBuffer[i]; } /* 冒泡法 */ for(i = 0; i < (const_array_size - 1); i ++) /* 冒泡的次數是(const_array_size-1)次 */ { for(k = 0; k < (const_array_size - 1 - i); k ++) { if(ucBuffer_3[const_array_size - 1 - k] > ucBuffer_3[const_array_size - 1 - 1 - k]) { ucTemp = ucBuffer_3[const_array_size - 1 - 1 - k]; ucBuffer_3[const_array_size - 1 - 1 - k] = ucBuffer_3[const_array_size - 1 - k]; ucBuffer_3[const_array_size - 1 - k] = ucTemp; } } } for(i = 0; i < const_array_size; i ++) /* 參與排序算法之后,把運算結果的數據全部搬移到輸出接口中,方便外面程序調用 */ { p_ucOutputBuffer[i] = ucBuffer_3[i]; } } /** * @brief 第4種方法 * @param p_ucInputAndOutputBuffer * @retval * 第4種方法.指針在函數的接口中,天生就是既可以做輸入,也可以是做輸出,它是雙向性的,類似全局變量的特點。 * 我們可以根據實際項目的情況,在必要的時候可以直接把輸入接口和輸出接口合并在一起, * 這種方法的缺點是沒有把輸入和輸出分開,沒有那么直觀。但是優點也是很明顯的,就是比較 * 省程序ROM容量和數據RAM容量,而且運行效率也比較快。現在介紹給大家。 * 本程序的*p_ucInputAndOutputBuffer是輸入輸出接口。 **/ void big_to_small_sort_4(unsigned char *p_ucInputAndOutputBuffer) { unsigned char i; unsigned char k; unsigned char ucTemp; /* 在兩兩交換數據的過程中,用于臨時存放交換的某個變量 */ /* 冒泡法 */ for(i = 0; i < (const_array_size - 1); i ++) /* 冒泡的次數是(const_array_size-1)次 */ { for(k = 0; k < (const_array_size - 1 - i); k ++) { if(p_ucInputAndOutputBuffer[const_array_size - 1 - k] > p_ucInputAndOutputBuffer[const_array_size - 1 - 1 - k]) { ucTemp = p_ucInputAndOutputBuffer[const_array_size - 1 - 1 - k]; p_ucInputAndOutputBuffer[const_array_size - 1 - 1 - k] = p_ucInputAndOutputBuffer[const_array_size - 1 - k]; p_ucInputAndOutputBuffer[const_array_size - 1 - k] = ucTemp; } } } } /** * @brief 串口服務程序 * @param 無 * @retval * 以下函數說明了,在空函數里,可以插入很多個return語句。 * 用return語句非常便于后續程序的升級修改。 **/ void usart_service(void) { unsigned char i = 0; // /*如果超過了一定的時間內,再也沒有新數據從串口來*/ // if(uiSendCnt >= const_receive_time && ucSendLock == 1) // { // 原來的語句,現在被兩個return語句替代了 if(uiSendCnt < const_receive_time) /* 延時還沒超過規定時間,直接退出本程序,不執行return后的任何語句。 */ { return; /* 強行退出本子程序,不執行以下任何語句 */ } if(ucSendLock == 0) /* 不是最新一次接收到串口數據,直接退出本程序,不執行return后的任何語句。 */ { return; /* 強行退出本子程序,不執行以下任何語句 */ } /* * 以上兩條return語句就相當于原來的一條if(uiSendCnt>=const_receive_time&&ucSendLock==1)語句。 * 用了return語句后,就明顯減少了一個if嵌套。 */ ucSendLock = 0; /*處理一次就鎖起來,不用每次都進來,除非有新接收的數據*/ /*下面的代碼進入數據協議解析和數據處理的階段*/ uiRcMoveIndex = 0; /*由于是判斷數據頭,所以下標移動變量從數組的0開始向最尾端移動*/ // /* // * 判斷數據頭,進入循環解析數據協議必須滿足兩個條件: // * 第一:最大接收緩沖數據必須大于一串數據的長度(這里是5。包括2個有效數據,3個數據頭) // * 第二:游標uiRcMoveIndex必須小于等于最大接收緩沖數據減去一串數據的長度(這里是5。包括2個有效數據,3個數據頭) // */ // while(uiRcregTotal >= 5 && uiRcMoveIndex <= (uiRcregTotal - 5)) // { // 原來的語句,現在被兩個return語句替代了 while(1) /* 死循環可以被以下return或者break語句中斷,return本身已經包含了break語句功能。 */ { if(uiRcregTotal < 5) /* 串口接收到的數據太少 */ { uiRcregTotal = 0; /*清空緩沖的下標,方便下次重新從0下標開始接受新數據*/ return; /* 強行退出while(1)循環嵌套,直接退出本程序,不執行以下任何語句 */ } if(uiRcMoveIndex > (uiRcregTotal - 5)) /* 數組緩沖區的數據已經處理完 */ { uiRcregTotal = 0; /*清空緩沖的下標,方便下次重新從0下標開始接受新數據*/ return; /* 強行退出while(1)循環嵌套,直接退出本程序,不執行以下任何語句 */ } /* * 以上兩條return語句就相當于原來的一條while(uiRcregTotal>=5&&uiRcMoveIndex<=(uiRcregTotal-5))語句。 * 以上兩個return語句的用法,同時說明了return本身已經包含了break語句功能,不管當前處于幾層的內部循環嵌套, * 都可以強行退出循環,并且直接退出本程序。 */ if(ucRcregBuf[uiRcMoveIndex + 0] == 0xeb && ucRcregBuf[uiRcMoveIndex + 1] == 0x00 && ucRcregBuf[uiRcMoveIndex + 2] == 0x55) { for(i = 0; i < const_array_size; i ++) /* 從串口接收到的需要被排序的原始數據 */ { ucUsartBuffer[i] = ucRcregBuf[uiRcMoveIndex+3+i]; } /* 第3種運算方法,依靠指針為函數增加一個數組的輸出接口 */ /* 通過指針輸出接口,排序運算后的結果直接從這個輸出口中導出到ucGlobalBuffer_3數組中 */ big_to_small_sort_3(ucUsartBuffer, ucGlobalBuffer_3); /* ucUsartBuffer是輸入的數組,ucGlobalBuffer_3是接收排序結果的數組 */ for(i = 0; i < const_array_size; i ++) { eusart_send(ucGlobalBuffer_3[i]); /* 把用第3種方法排序后的結果返回給上位機觀察 */ } /* 為了方便上位機觀察,多發送3個字節ee ee ee作為第1種方法與第2種方法的分割線 */ eusart_send(0xee); eusart_send(0xee); eusart_send(0xee); /* 第4種運算方法,依靠一個指針作為函數的輸入輸出接口。 */ /* 通過這個指針輸入輸出接口,ucGlobalBuffer_4數組既是輸入數組,也是輸出數組,排序運算后的結果直接存放在它本身,類似于全局變量的特點。 */ for(i = 0; i < const_array_size; i ++) /* 從串口接收到的需要被排序的原始數據 */ { ucGlobalBuffer_4[i] = ucUsartBuffer[i]; } big_to_small_sort_4(ucGlobalBuffer_4); /* ucUsartBuffer是輸入的數組,ucGlobalBuffer_3是接收排序結果的數組 */ for(i = 0; i < const_array_size; i ++) { eusart_send(ucGlobalBuffer_4[i]); /* 把用第3種方法排序后的結果返回給上位機觀察 */ } break; /*退出while(1)循環*/ } uiRcMoveIndex ++; /*因為是判斷數據頭,游標向著數組最尾端的方向移動*/ } // } uiRcregTotal = 0; /*清空緩沖的下標,方便下次重新從0下標開始接受新數據*/ // } } /** * @brief 定時器0中斷函數 * @param 無 * @retval 無 **/ void ISR_T0(void) interrupt 1 { TF0 = 0; /*清除中斷標志*/ TR0 = 0; /*關中斷*/ if(uiSendCnt < const_receive_time) /*如果超過這個時間沒有串口數據過來,就認為一串數據已經全部接收完*/ { uiSendCnt ++; /*表面上這個數據不斷累加,但是在串口中斷里,每接收一個字節它都會被清零,除非這個中間沒有串口數據過來*/ ucSendLock = 1; /*開自鎖標志*/ } if(uiVoiceCnt != 0) { uiVoiceCnt --; BEEP = 0; } else { ; BEEP = 1; } TL0 = T1MS; /*initial timer0 low byte*/ TH0 = T1MS >> 8; /*initial timer0 high byte*/ TR0 = 1; /*開中斷*/ } /** * @brief 串口接收數據中斷 * @param 無 * @retval 無 **/ void usart_receive(void) interrupt 4 { if(RI == 1) { RI = 0; ++ uiRcregTotal; if(uiRcregTotal > const_rc_size) { uiRcregTotal = const_rc_size; } ucRcregBuf[uiRcregTotal - 1] = SBUF; /*將串口接收到的數據緩存到接收緩沖區里*/
上一篇:為指針加上緊箍咒const,避免意外修改了只做輸入接口的數據
下一篇:指針的第三大好處,指針作為數組在函數中的輸出接口
推薦閱讀
史海拾趣
在電子行業中,艾迪沃德公司(Beijing IDworld Science & Technology Development Co., Ltd.)的發展歷程充滿了技術創新與市場拓展的亮點。以下是五個關于艾迪沃德公司發展起來的相關故事,每個故事均基于事實描述,旨在展現其成長軌跡。
1. 創立與技術創新起點
艾迪沃德公司成立于2004年6月,自創立之初便確立了以研究、開發國際先進指紋識別技術為基本戰略的發展方向。在那個指紋識別技術剛剛興起的時代,艾迪沃德憑借其前瞻性的視野,迅速投入到這一領域的探索中。公司自主研發的指紋識別技術,經過不斷迭代與優化,逐漸成為了業界公認的優秀指紋識別核心算法之一。這一技術突破不僅為公司贏得了市場的初步認可,更為后續的產品開發奠定了堅實的基礎。
2. 產品多元化與市場拓展
隨著技術的不斷成熟,艾迪沃德開始將指紋識別技術應用于更多領域,推出了包括指紋考勤機、指紋門禁系統、指紋保險柜在內的多元化產品系列。這些產品憑借其高安全性、便捷性和穩定性,迅速在市場中占據了一席之地。特別是在安防、金融、教育等行業,艾迪沃德的產品得到了廣泛應用,進一步鞏固了其在指紋識別領域的市場地位。
3. OEM與ODM業務的發展
為了滿足不同客戶的定制化需求,艾迪沃德積極拓展OEM(原始設備制造商)和ODM(原始設計制造商)業務。公司憑借其強大的研發能力和生產能力,為眾多合作伙伴提供從產品設計、生產到售后的全方位服務。這一業務模式不僅為公司帶來了穩定的收入來源,還進一步提升了艾迪沃德在電子行業中的知名度和影響力。
4. 技術支持與解決方案提供
艾迪沃德深知技術支持對于客戶的重要性,因此公司組建了一支專業的技術支持團隊,為客戶提供包括技術咨詢、方案設計、系統集成在內的全方位服務。無論是大型項目還是小型應用,艾迪沃德都能根據客戶的具體需求,提供量身定制的解決方案。這種以客戶為中心的服務理念,贏得了客戶的廣泛贊譽和信賴。
5. 國際合作與品牌建設
在國際化戰略的推動下,艾迪沃德積極參與國際交流與合作,與多家國際知名企業建立了良好的合作關系。通過引進國外先進技術和管理經驗,艾迪沃德不斷提升自身的競爭力和創新能力。同時,公司還加大了品牌建設的力度,通過參加國際展會、發布新品等方式,提升品牌知名度和美譽度。這些努力不僅為公司帶來了更多的國際合作機會,也為艾迪沃德在全球電子行業中樹立了良好的品牌形象。
1966年,Coherent Inc.由一群斯坦福大學的研究人員共同創立,其中包括物理學家James Hobart。初創時期的公司致力于激光技術的研究和開發,逐漸積累起了豐富的技術底蘊。這種對技術的執著追求和不斷探索,為公司的后續發展奠定了堅實的基礎。
Easy Magnet Corp公司最初由幾位熱衷于磁性材料研究的科學家和工程師創立。他們發現了一種新型磁性材料,具有極高的磁導率和穩定性。基于這一發現,他們開始研發適用于電子產品的磁性元件。最初的產品雖然簡單,但因其高性能和可靠性,很快在市場中獲得了認可。隨著訂單的增加,公司逐漸擴大了生產規模,并開始了技術研發的深入探索。
Easy Magnet Corp公司深知人才是企業發展的核心動力。因此,公司注重人才培養和引進,建立了一支高素質、專業化的研發團隊。同時,公司還為員工提供了良好的工作環境和福利待遇,激發了員工的工作熱情和創造力。這些舉措為公司的發展提供了堅實的人才保障。
隨著市場需求的不斷變化,Easy Magnet Corp公司意識到,只有不斷創新才能保持競爭優勢。因此,公司加大了研發投入,不斷推出具有創新性的產品。其中,一款集成了微型化、高性能和高穩定性的磁性傳感器,因其獨特的優勢,在智能手機、平板電腦等電子產品中得到了廣泛應用。這一技術突破不僅提升了公司的知名度,也為公司帶來了可觀的收益。
隨著技術的不斷進步,Diodes Incorporated始終保持著對新技術研發的投入。其中,公司推出的首款碳化硅(SiC)蕭特基勢壘二極管(SBD)就是一個重要的里程碑。這款產品的推出,不僅大幅提高了半導體器件的效率和高溫可靠性,還滿足了市場對降低系統執行成本和減少維護需求的期望。這一技術創新的突破,進一步鞏固了Diodes Incorporated在半導體行業中的領先地位。
2.物體帶電與電場感應 從原理上說,絕對不帶電的物體是不存在的,任何物體都會不知不覺地就會帶上電。每種物質都有一個代表自己性質的位能,兩種不同性質的物體靠近在一起就會產生“接點電位差”。當兩種不同性質的物體接觸在一起時,這兩種物質 ...… 查看全部問答∨ |
|
WriteFile寫并口打印(windows字體)時,出現漏打印問題。 大家好,第一次發帖,請多關照。 現象描述: PC端并口連接設備打印機(設備自帶打印機),生產過程中實時發送Windows字體的漢字(例如 張三),隨機出現漏打印,即設備返回執行成功,但色帶打印機并沒有真正打印出來。 軟件結構: VB主動程序,D ...… 查看全部問答∨ |
我要用到一個開源包(GeoPad),開發環境為EVC+PPC2003模擬器,所給開發包SDK中包括了3個DLL(GeoPAD.DLL,GeoPADVB.NET.DLL,和GeoPADVC.NET.DLL)和一個.h文件(定義了一個類GeoPADCtrl),還分別給了C#和c++版的2個例程。 C#版的例程將GeoPADVB.NET. ...… 查看全部問答∨ |
位圖問題,想在uboot啟動的時候把一張圖片顯示到LCD上面。這時候系統還沒有起來,不知道程序怎么寫? 我現在能想到的方案是這樣的: @ 把bitmap圖像的數據用數組的形式組織起來,然后把這些數據丟到顯示緩存上面。然后讓其顯示在lcd上面。 現在遇到的問題是, 1;不知道bimap的數據是怎樣組織的。用UltraEdit打開一張bitmap位圖,里面的數據看不懂 ...… 查看全部問答∨ |
我在用KEIL編程的時候,發現mian.c函數的前面有三個點, 后面查資料說是沒有參與編譯。 如圖 下載 (9.33 KB) 2010-10-1 20:44 請問下KEIL是在哪里設置函數是否參與編譯? 謝謝。… 查看全部問答∨ |
用并口仿真器,利用IAR C3.41A的Debug向msp430f2274下載仿真代碼,總是提示沒有連接的設備。線路經過反復檢查,沒有錯誤。借了一個USB的仿真器后,選擇4線JTAG方式,可以順利下載仿真。不知用并口仿真器仿真msp430f2274時軟件、硬件有什么具體設置 ...… 查看全部問答∨ |
altium designer中關于polygon和焊盤間距的布線規則的設置 步驟如下:— Design》Rules》Design Rules》Electrical》Clearances— 右鍵單擊鼠標,而后選擇*New Rule*即添加了新的間距規則— 在上面的where the first object matches選項里選advanced,query builder>>下拉菜單-object kind is 后面選pol ...… 查看全部問答∨ |
設計資源 培訓 開發板 精華推薦
- 觀展有禮 | 到 e 絡盟展臺,領星巴克咖啡券(上海慕尼黑電子展)
- 感謝有你,感恩龍年,EEWORLD陪你一起“鬧”龍年!
- 合泰ESK32-360 開發板“拍了拍”你,免費測評在等你
- 艾睿電子線上研討會:英特爾FPGA深度學習加速技術 7月30日上午10:00-11:30 期待您的蒞臨!
- 學習有禮,分享也有禮!跟著小梅哥,一起intel SoC FPGA走起!
- TE Connectivity利用傳感和連接解決方案,賦能電動汽車發展 參與有好禮!
- Discover mmWave 走進 TI 毫米波雷達世界 快速獲得設計技能
- 現場抽取PS5等諸多好禮 SiFive RISC-V 中國技術論壇 上海、北京、深圳 3場線下活動邀您出席!
- 微信直播慕尼黑東芝大展臺,好禮多多等你來