51單片機學習--定時器--中斷--串口通信


51單片機學習–定時器–中斷–串口通信

定時器–中斷–串口通信

中斷分類

定時器中斷 外部中斷 串口中斷

  1. 基本概念
    對於單片機來講, 中斷是指 CPU 在處理某一事件 A 時, 發生了另一事件 B,
    請求 CPU 迅速去處理(中斷發生); CPU 暫時停止當前的工作(中斷響應), 轉去
    處理事件 B(中斷服務); 待 CPU 將事件 I 處理完畢后, 再回到原來事件 A 被
    中斷的地方繼續處理事件 A(中斷返回), 這一過程稱為中斷。
  2. 學習目的
    中斷是為使單片機具有對外部或內部隨機發生的事件實時處理而設置的,
    中斷功能的存在, 很大程度上提高了單片機處理外部或內部事件的能力。 它也是
    單片機最重要的功能之一, 是我們學習單片機必須要掌握的。
    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳在這里插入圖片描述
  3. 流程圖
    在這里插入圖片描述
  4. 中斷系統-中斷源
    引起 CPU 中斷的根源稱為中斷源。 中斷源向 CPU 提出中斷請求, CPU 暫時
    中斷原來的事務 A, 轉去處理事件 B, 對事件 B 處理完畢后, 再回到原來被中斷
    的地方(即斷點), 稱為中斷返回。 實現上述中斷功能的部件稱為中斷系統(中斷
    機構)。
  5. 優點
    ①分時操作。 CPU 可以分時為多個 I/O 設備服務, 提高了計算機的利用率;
    ②實時響應。 CPU 能夠及時處理應用系統的隨機事件, 系統的實時性大大增
    強;
    ③可靠性高。 CPU 具有處理設備故障及掉電等突發性事件能力, 從而使系統
    可靠性提高。
  6. STC89C5X系列單片機一般配置
    51 系列單片機一定有基本的 5 個中斷, 但不全有 8 個中斷, 需要查看芯片手冊,基本的 5 個中斷: INT0、 INT1、 定時器 0/1, 串口中斷。
    基本類型單片機的中斷有2個中斷優先級。
    用戶可以用關總中斷允許位(EA/IE.7)或相應中斷的允許位來屏蔽所有的中斷請求, 也可以用打開相應的中斷允許位來使 CPU 響應相應的中斷申請。 其中有些中斷源可以用軟件獨立地控制為開中斷或關中斷狀態。 每一個中斷的優先級別均可用軟件設置。
    高優先級的中斷請求可以打斷低優先級的中斷, 反之, 低優先級的中斷請求不可以打斷高優先級及同優先級的中斷。 當兩個相同優先級的中斷同時產生時, 將由查詢次序來決定系統先響應哪個中斷。 STC89C5X 系列單片機的各個中斷查詢次序表如下圖所示:
    在這里插入圖片描述
  7. 傳統51單片機的5個基本中斷源的理解
    在這里插入圖片描述
    ①INT0 對應的是 P3.2 口的附加功能, 可由 IT0(TCON.0)選擇其為低電平有
    效還是下降沿有效。 當 CPU 檢測到 P3.2 引腳上出現有效的中斷信號時, 中斷標
    志 IE0(TCON.1)置 1, 向 CPU 申請中斷。
    ②INT1 對應的是 P3.3 口的附加功能, 可由 IT1(TCON.2)選擇其為低電平有
    效還是下降沿有效。 當 CPU 檢測到 P3.3 引腳上出現有效的中斷信號時, 中斷標
    志 IE1(TCON.3)置 1,向 CPU 申請中斷。
    ③T0 對應的是 P3.4 口的附加功能, TF0(TCON.5) ,片內定時/計數器 T0 溢
    出中斷請求標志。 當定時/計數器 T0 發生溢出時, 置位 TF0, 並向 CPU 申請中斷。
    ④T1 對應的是 P3.5 口的附加功能, TF1( TCON.7) , 片內定時/計數器 T1
    溢出中斷請求標志。 當定時/計數器 T1 發生溢出時, 置位 TF1, 並向 CPU 申請中
    斷。
    ⑤RXD 和 TXD 對應對應的是 P3.0 和 P3.1 口的附加功能, RI(SCON.0) 或 TI
    (SCON.1) , 串行口中斷請求標志。 當串行口接收完一幀串行數據時置位 RI 或
    當串行口發送完一幀串行數據時置位 TI, 向 CPU 申請中斷。
  8. 中斷允許控制
    CPU 對中斷系統所有中斷以及某個中斷源的開放和屏蔽是由中斷允許寄存器IE控制。
    在這里插入圖片描述
    EX0(IE.0), 外部中斷 0 允許位;
    ET0(IE.1), 定時/計數器 T0 中斷允許位;
    EX1(IE.2), 外部中斷 0 允許位;
    ET1(IE.3), 定時/計數器 T1 中斷允許位;
    ES(IE.4), 串行口中斷允許位;
    EA (IE.7), CPU 中斷允許(總允許)位。
  9. 中斷請求標志 TCON
    在這里插入圖片描述
    IT0(TCON.0) , 外部中斷 0 觸發方式控制位。
    當 IT0=0 時, 為電平觸發方式。
    當 IT0=1 時, 為邊沿觸發方式(下降沿有效) 。
    IE0(TCON.1) , 外部中斷 0 中斷請求標志位。
    IT1(TCON.2) , 外部中斷 1 觸發方式控制位。
    IE1(TCON.3) , 外部中斷 1 中斷請求標志位。
    TF0(TCON.5) , 定時/計數器 T0 溢出中斷請求標志位。
    TF1(TCON.7) , 定時/計數器 T1 溢出中斷請求標志位。
  10. 中斷優先級
    在這里插入圖片描述
  11. 中斷號
    在這里插入圖片描述
  12. 中斷響應條件
    ①中斷源有中斷請求;
    ②此中斷源的中斷允許位為1;
    ③CPU 開中斷(即 EA=1)。
  13. 中斷源入口地址
    中斷源 入口地址
    外部中斷0 0003H
    定時器T0中斷 000BH
    外部中斷1 0013H
    定時器T1中斷 001BH
    串行口中斷 0023H

軟件代碼分析

一般具有的框架

//主程序中需要有以下代碼:
EA=1//打開總中斷開關
EX0=1//開外部中斷 0
IT0=0/1//設置外部中斷的觸發方式普中 51 單片機開發攻略
//中斷服務函數
void int0() interrupt 0 using 1
{
    // 編寫用戶所需的功能代碼
}

注意:在中斷函數中 int0 是函數名,可自定義,但必須符合 C 語言標識符定義規則, interrupt 是一個關鍵字, 表示 51 單片機中斷。 后面的“0” 是中斷號, 外部中斷 0 中斷號為 0, 這個可參考前面的內容。后面的 using 1 可省略不寫。

外部中斷

void Int0Init()

{
    //設置 INT0
    IT0=1;//跳變沿出發方式(下降沿)
    EX0=1;//打開 INT0 的中斷允許。
    EA=1;//打開總中斷
} 

//觸發中斷后即會進入中斷服務函數, 外部中斷 0 中斷服務函數如下:
void Int0() interrupt 0 //外部中斷 0 的中斷函數
{
    //執行所需的功能
}

定時器

  1. 基本概念
    ①振盪周期: 為單片機提供定時信號的振盪源的周期(晶振周期或外加振盪
    周期) 。
    ②狀態周期: 2 個振盪周期為 1 個狀態周期, 用 S 表示。 振盪周期又稱 S 周
    期或時鍾周期。
    ③機器周期: 1 個機器周期含 6 個狀態周期, 12 個振盪周期。
    ④指令周期: 完成 1 條指令所占用的全部時間, 它以機器周期為單位。
    例如: 外接晶振為 12MHz 時, 51 單片機相關周期的具體值為:
    振盪周期=1/12us;
    狀態周期=1/6us;
    機器周期=1us;
    指令周期=1~4us;
  2. 注意
    ①51 單片機有兩組定時器/計數器, 因為既可以定時, 又可以計數, 故稱之
    為定時器/計數器。
    ②定時器/計數器和單片機的 CPU 是相互獨立的。 定時器/計數器工作的過程
    是自動完成的, 不需要 CPU 的參與。
    ③51 單片機中的定時器/計數器是根據機器內部的時鍾或者是外部的脈沖信
    號對寄存器中的數據加 1。
  3. 原理
    STC89C5X 單片機內有兩個可編程的定時/計數器T0、T1和一個特殊功能定時器 T2。定時/計數器的實質是加 1 計數器(16 位),由高 8 位和低 8 位兩個寄存器 THx 和 TLx 組成。 它隨着計數器的輸入脈沖進行自加 1, 也就是每來一個脈沖, 計數器就自動加 1, 當加到計數器為全 1 時, 再輸入一個脈沖就使計數器回零, 且計數器的溢出使相應的中斷標志位置 1, 向 CPU 發出中斷請求(定時/計數器中斷允許時) 。 如果定時/計數器工作於定時模式, 則表示定時時間已到;如果工作於計數模式, 則表示計數值已滿。 可見, 由溢出時計數器的值減去計數初值才是加 1 計數器的計數值。
  4. 定時器/計數器內部結構
    在這里插入圖片描述
    T0 和 T1 引腳對應的是單片機 P3.4 和 P3.5 管腳.
    51單片機定時器/計數器:兩個特殊功能寄存器控制。
    TMOD 是定時/計數器的工作方式寄存器, 確定工作方式和功能;
    TCON 是控制寄存器, 控制 T0、 T1 的啟動和停止及設置溢出標志;
  5. TMOD寄存器 工作方式寄存器
    工作方式寄存器 TMOD 用於設置定時/計數器的工作方式, 低四位用於 T0, 高
    四位用於 T1。
    GATE=0;(不需要外部中斷INT0/1引腳為高電平)
    用於控制定時器的啟動是否受外部中斷源信號的影響。只要用軟件使 TCON 中的 TR0或TR1為1,就可以啟動定時/計數器工作;
    GATE=1;
    要用軟件使TR0或TR1為1.同時外部中斷引腳 INT0/1 也為高電平時,才能啟動定時/計數器工作.即此時定時器的啟動條件,加上了INT0/1引腳為高電平這一條件;

C/T :定時/計數模式選擇位。
C/T =0 為定時模式;
C/T =1 為計數模式;

在這里插入圖片描述
在這里插入圖片描述

M1M0:工作方式設置位:定時器/計數器共有4種方式。
M1M0 工作方式計數器模式 TMOD(設置定時器模式)
0 0 方式0 13位計數器 TMOD=0x00
0 1 方式1 16位計數器 TMOD=0x01
1 0 方式2 自動重裝8位計數器 TMOD=0x02
1 1 方式3 T0分為2個8位獨立計數器,T1為無中斷重裝8位計數器 TMOD=0x03

  1. 控制寄存器 TCON
    TCON 的低 4 位用於控制外部中斷,已在前面介紹。 TCON 的高 4 位用於控制定
    時/計數器的啟動和中斷申請。
    在這里插入圖片描述
    TCON寄存器高四位
    TF1(TCON.7):T1溢出中斷請求標志位。T1計數溢出時由硬件自動置TF1
    為 1。 CPU 響應中斷后TF1由硬件自動清0。T1工作時,CPU可隨時查詢 TF1 的狀態。 所以, TF1 可用作查詢測試的標志。 TF1 也可以用軟件置 1 或清 0, 同硬件置 1 或清 0 的效果一樣。
    TR1(TCON.6):T1 運行控制位。 TR1 置 1 時, T1 開始工作; TR1 置 0 時,T1 停止工作。 TR1 由軟件置 1 或清 0。 所以, 用軟件可控制定時/計數器的啟動與停止。
    TF0(TCON.5) : T0 溢出中斷請求標志位, 其功能與 TF1 類同。
    TR0(TCON.4) : T0 運行控制位, 其功能與 TR1 類同。

TR1,TR0=0;關閉定時器1,0
TR1,TR0=1;打開定時器1,0

  1. 定時器/計數器工作方式
方式0

方式 0 為 13 位計數, 由 TL0 的低 5 位(高 3 位未用) 和 TH0 的 8 位組成。TL0 的低 5 位溢出時向 TH0 進位, TH0 溢出時, 置位 TCON 中的 TF0 標志, 向 CPU發出中斷請求。
在這里插入圖片描述

方式1

方式 1 的計數位數是 16 位, 由 TL0 作為低 8 位, TH0 作為高 8 位, 組成了16 位加 1 計數器。
在這里插入圖片描述

方式2

方式 2 為自動重裝初值的 8 位計數方式。 工作方式 2 特別適合於用作較精確的脈沖信號發生器。
在這里插入圖片描述

方式3

方式 3 只適用於定時/計數器 T0, 定時器 T1 處於方式 3 時相當於 TR1=0,
停止計數。 工作方式 3 將 T0 分成為兩個獨立的 8 位計數器 TL0 和 TH0。
在這里插入圖片描述

  1. 單片機編寫定時器程序時一些步驟
    對TMOD賦值,以確定T0和T1的工作方式;
    計算初值,並將初值寫入TH0,TL0或者TH1,TL1;
    中斷方式時,則對IE賦值,開放中斷
    使TR0或TR1置位,啟動定時器/計數器定時或者計數。
  2. 應用
    應用較多的是方式 1 和方式 2。 定時器中通常使用定時器方式 1, 串口通信中通常使用方式 2。

定時器配置

步驟

①對 TMOD 賦值,以確定 T0 和 T1 的工作方式,如果使用定時器0即對T0配置, 如果使用定時器 1 即對 T1 配置。
②根據所要定時的時間計算初值,並將其寫入 TH0、 TL0 或 TH1、 TL1。
③如果使用中斷, 則對 EA 賦值, 開放定時器中斷。
④使 TR0 或 TR1 置位, 啟動定時/計數器定時或計數。

初值的計算:

TH0=(65536-50000)/256; //裝定時器初值高8位
TL0=(65536-50000)%256; //裝定時器初值低8位 
TH0=(65536-T0)/256 ;//裝定時器初值高8位
TL0=(65536-T0)%256 ;//裝定時器初值低8位
//其中T0是需要計算的時間
//一般編程過程並直接計算T0的值,直接寫讓單片機自己去計算
//定時器0中斷函數 
void T0/T1_time() interrupt 1//使用定時器中斷1
{
    
    TMOD=0X01;//選擇了定時器0 方式1
    //可以設置TMOD=0x00;0x01;0x10;0x11;共四組方式
    
    TH0=(65536-T0)/256;   //裝定時器初值高8位
	TL0=(65536-T0)%256;    //裝定時器初值低8位
    //T0是需要計算的時間
    uchar count=0;
    if(count==X)
    
    {
        count=0; //清0重新計數
        執行程序代碼
    }
    //其中X是需要計算次數,比如讓定時器定時個1s;
    //則需要定時器一個50ms的時間;
    //如果要達成1s則需要執行20次;
    //讓定時器定時個50ms時間,需要這樣去寫
    //TH0=(65536-50000)/256;
    //TL0=(65536-50000)%256;
    //讓定時器定時個T0時間,需要這樣去寫
    //
     //TH0=(65536-T0乘10的3次方)/256;
    //TL0=(65536-T0乘10的3次方)%256;
// 使用定時器0
//配置定時器0工作方式1,設置1ms的初值,打開定時器計數器功能
void Timer0Init()
{
    TMOD|=0X01;//選擇為定時器 0 模式, 工作方式 1, 僅用 TR0 打開啟動。
    TH0=0XFC; //給定時器賦初值, 定時 1ms
    TL0=0X18;
    ET0=1;//打開定時器 0 中斷允許
    EA=1;//打開總中斷普中 51 單片機開發攻略
    TR0=1;//打開定時器
}

簡單案例

/**************************************************************** ********************** 實驗現象: 下載程序后, D1 小燈循環點亮 1 秒, 熄滅 1 秒。 使用單片機內部 定時器可以實現准確延時 接線說明: (具體接線圖可見開發攻略對應實驗的“實驗現象” 章節) 1, 單片機-->LED&交通燈模塊 P20-->D1 注意事項: ***************************************************************** **********************/
#include "reg52.h" //此文件中定義了單片機的一些特殊功能寄存器
typedef unsigned int u16; //對數據類型進行聲明定義
typedef unsigned char u8;
sbit led=P2^0; //定義 P20 口是 led
/**************************************************************** *************** * 函 數 名 : Timer0Init * 函數功能 : 定時器 0 初始化 * 輸 入 : 無 * 輸 出 : 無 ***************************************************************** **************/
void Timer0Init()
{
    TMOD|=0X01;//選擇為定時器 0 模式, 工作方式 1, 僅用 TR0 打開啟動。
    TH0=0XFC; //給定時器賦初值, 定時 1ms
    TL0=0X18;
    ET0=1;//打開定時器 0 中斷允許
    EA=1;//打開總中斷
    TR0=1;//打開定時器
}
/**************************************************************** *************** * 函 數 名 : main * 函數功能 : 主函數 * 輸 入 : 無 * 輸 出 : 無 ***************************************************************** **************/
void main()
{
    Timer0Init(); //定時器 0 初始化
    while(1);
}
/**************************************************************** *************** * 函 數 名 : void Timer0() interrupt 1 * 函數功能 : 定時器 0 中斷函數 * 輸 入 : 無 * 輸 出 : 無 ***************************************************************** **************/
void Timer0() interrupt 1
{
    static u16 i;
    TH0=0XFC; //給定時器賦初值, 定時 1ms
    TL0=0X18;
    i++;
    if(i==1000)
    {
        i=0;
        led=~led;
    }
}

串口中斷(目前還沒有寫)

串口相關寄存器

  1. 串口控制寄存器SCON

  2. 電源控制寄存器PCON

串口工作方式

1.方式0
2.方式1
3.方式2
4.方式4

串口初始化

步驟
①確定 T1 的工作方式(TMOD 寄存器) ;
②確定串口工作方式(SCON 寄存器) ;普中 51 單片機開發攻略
③計算 T1 的初值(設定波特率) , 裝載 TH1、 TL1;
④啟動 T1(TCON 中的 TR1 位) ;
⑤如果使用中斷, 需開啟串口中斷控制位(IE 寄存器)。

串口初始化案例

void UsartInit()
{
    SCON=0X50; //設置為工作方式 1
    TMOD=0X20; //設置計數器工作方式 2
    PCON=0X80; //波特率加倍
    TH1=0XF3; //計數器初始值設置, 注意波特率是 4800 的
    TL1=0XF3;
    ES=1; //打開接收中斷
    EA=1; //打開總中斷
    TR1=1; //打開計數器
}

串口中斷方式案例

#include <reg52.h>
#define FOSC 12000000UL 
#define BAUD 2400UL 
void  UsartConfiguration(void)				//串口初始化
{
		 TMOD&=0x0F;      //定時器1模式控制在高4位
		 TMOD|=0x20;      //定時器1工作在模式2,自動重裝模式
		 SCON=0x50;       //串口工作在模式1
		 TH1=256-FOSC/(BAUD*12*16);  //計算定時器重裝值
		 TL1=256-FOSC/(BAUD*12*16);
		 PCON|=0x80;    //串口波特率加倍
		 ES=1;         //串行中斷允許
		 TR1=1;        //啟動定時器1
		 REN=1;        //允許接收 
		 EA=1;         //允許中斷
}
void InterruptUART() interrupt 4 //中斷源是4
{
	//unsigned char receive_data;
	if(RI)
	{
	 	RI = 0;
		SBUF = SBUF;
		//receive_data = SBUF;//接收到的數據
		//if(receive_data == '1') 
		//{
    // LED1 = 0;
    // DELAY_nMS(500);
    // LED1=1;
    //}
// if(receive_data == ' ') //接受一個字符 
// {
// //執行代碼,你想要的控制的東西,例如led,蜂鳴器,等傳感器 
// } 
	 }
	//EA=1;
	if(TI)
	{
		TI=0;	
	}		
}

void main()
{
	UsartConfiguration();
	while(1)
	{
		;
	}
	
}

軟件代碼

簡單實現定時器led

#include"reg51.h"

sbit led=P1^1;//定義一個LED燈為1.1引腳
#define uchar unsigned char
//#define uint unsigned int
uchar num;//定義全局變量

void timer0Iint()//定時器0的初始化函數
{   
    TMOD=0x01;//設置定時器0為工作方式1(M1 M0為01)
    TH0=(65536-50000)/256;//裝初值11.0582晶振定時50ms數為45872
    TL0=(65536-50000)%256;
    EA=1;//開總中斷
    ET0=1;//開定時器0中斷
}

void T0_time() interrupt 1
{
       num++;//num每加一次判斷一次是否到20次
      if(num==20)//如果到了20次,說明1秒時間到
        {
            num=0;//num清0重新計數
            led=~led;
        }
}

void main()
{
     timer0Iint();
     TR0=1;//啟動定時器0//該步驟也可在初始化寫
    while(1)
    {
    }//程序停止在這里等待中斷發生
 } 

一些案例

  1. 普中單片機串口接收數據控制燈亮滅
/*----------------------------------------------------------------------------- * 實 驗 名 : 串口試驗 * 實驗說明 : 普中單片機串口接收數據控制燈亮滅 * 連接方式 : * 注 意 : 該試驗使用的晶振是12MHZ *******************************************************************************/
 
#include<reg52.h>
#include<intrins.h>
 
#define uchar unsigned char
#define uint unsigned int
	

#define jingzhen 12000000UL /*使用12.0M晶體*/ 
#define botelv 4800UL /*波特率定義為4800*/
 
uchar PuZh[] = "www.lemonhubs.github.io";
 
//--定義使用的IO--//
 
sbit LED1=P2^0;
sbit LED2=P2^1;
sbit LED3=P2^2;
 
//--聲明全局函數--// 
void UsartConfiguration();
void Delay_1ms(uint i);


void DELAY_nMS(unsigned int time);
 
/******************************************************************** * 名稱 : Com_Int() * 功能 : 串口中斷子函數 * 輸入 : 無 * 輸出 : 無 ***********************************************************************/
void Com_Int(void) interrupt 4
{
	uchar i;
  uchar receive_data;
	
  EA = 0;
	
  if(RI == 1) //當硬件接收到一個數據時,RI會置位
	{ 		
			RI = 0;
			receive_data = SBUF;//接收到的數據
			
		if(receive_data == '1')	 
		{
				LED1= 0;
			  DELAY_nMS(500);
				LED2= 0;
			 DELAY_nMS(500);
				LED3= 1;
			 DELAY_nMS(500);
		}
		else
		{
				LED1 = 1; 
			 DELAY_nMS(500);
			  LED2 = 1; 
			 DELAY_nMS(500);
			  LED3 = 0; 
			 DELAY_nMS(500);
		}
		
	}
		
		for(i=0; i<36; i++)
		{
			SBUF = PuZh[i];   //將要發送的數據放入到發送寄存器
			while(!TI);		    //等待發送數據完成
			TI=0;			        //清除發送完成標志位
			Delay_1ms(1);
		}
		EA = 1;
}
 
/******************************************************************************* * 函 數 名 : main * 函數功能 : 主函數 * 輸 入 : 無 * 輸 出 : 無 *******************************************************************************/
 
void main()
{
 
	UsartConfiguration();//初始化串口
	
	while(1);	
}
	
/******************************************************************************* * 函 數 名 : UsartConfiguration() * 函數功能 : 設置串口 * 輸 入 : 無 * 輸 出 : 無 *******************************************************************************/


void  UsartConfiguration(void)				//串口初始化
{
		 EA=0;            //暫時關閉中斷
		 TMOD&=0x0F;      //定時器1模式控制在高4位
		 TMOD|=0x20;      //定時器1工作在模式2,自動重裝模式
		 SCON=0x50;       //串口工作在模式1
		 TH1=256-jingzhen/(botelv*12*16);  //計算定時器重裝值
		 TL1=256-jingzhen/(botelv*12*16);
		 PCON|=0x80;    //串口波特率加倍
		 ES=1;         //串行中斷允許
		 TR1=1;        //啟動定時器1
		 REN=1;        //允許接收 
		 EA=1;         //允許中斷
}
 
 
/******************************************************************** * 名稱 : Delay_1ms() * 功能 : 延時子程序,延時時間為 1ms * x * 輸入 : x (延時一毫秒的個數) * 輸出 : 無 ***********************************************************************/
void Delay_1ms(uint i)//1ms延時
{
  uchar x,j;
  
  for(j=0;j<i;j++)
    for(x=0;x<=148;x++);
}

void DELAY_nMS(unsigned int time)
{
  unsigned int  i,j;             
  for(i=0;i<time;i++)    
     for(j=0;j<939;j++); 
}
  1. 普中單片機—串口通信(1)–通過按鍵控制發送
#include <reg52.h>

#define jingzhen 12000000UL /*使用12.0M晶體*/ 
#define botelv 4800UL /*波特率定義為4800*/
 
unsigned char zifu='a';			//待顯示字符

volatile unsigned char sending;

sbit S4=P3^2;//setting a key

void delay(unsigned char i)//延遲函數
{
	unsigned char j,k;
	for(j=i;j>0;j--)
		for(k=90;k>0;k--);
}
/************************************************************************* 函數名稱:UART_init 函數功能:串口初始化 **************************************************************************/

void UART_init(void)				//串口初始化
{
		 EA=0;            //暫時關閉中斷
		 TMOD&=0x0F;      //定時器1模式控制在高4位
		 TMOD|=0x20;      //定時器1工作在模式2,自動重裝模式
		 SCON=0x50;       //串口工作在模式1
		 TH1=256-jingzhen/(botelv*12*16);  //計算定時器重裝值
		 TL1=256-jingzhen/(botelv*12*16);
		 PCON|=0x80;    //串口波特率加倍
		 ES=1;         //串行中斷允許
		 TR1=1;        //啟動定時器1
		 REN=1;        //允許接收 
		 EA=1;         //允許中斷
}
/************************************************************************* 函數名稱:UART_Send_char 函數功能:發送一個字符 **************************************************************************/
void UART_Sendchar(unsigned char d)		  //發送一個字節的數據,形參d即為待發送數據。
{
	 SBUF=d; //將數據寫入到串口緩沖
	 sending=1;	 //設置發送標志
	 while(sending); //等待發送完畢
}
/************************************************************************* 函數名稱:UART_SendString 函數功能:發送一個字符串 **************************************************************************/
void UART_SendString(unsigned char *String)
{
    while(*String)
    {
        UART_Sendchar(*String);
        String++;
    }
}

/************************************************************************* 函數名稱:UART_SendLine 函數功能:串口發送換行 **************************************************************************/
void UART_SendLine(void)
{
    UART_Sendchar(0x0D);
    UART_Sendchar(0x0A);
}

//*********************************************************************************** 
函數名稱:UART_SendIntNumber
函數功能:串口發送整型數字
//*********************************************************************************** 
void UART_SendIntNumber(int Number)
{
    unsigned char NumbArray[6]={0};    // 定義局部數組,用於數據存儲
    if(Number<0)
    {
        Number=0-Number;
        UART_Sendchar('-');
    }
    else
    {
       UART_Sendchar('+');
    }
    
    NumbArray[0]=(Number/10000)%10+0x30; 
    NumbArray[1]=(Number/1000) %10+0x30;
    NumbArray[2]=(Number/100)  %10+0x30;
    NumbArray[3]=(Number/10)   %10+0x30;
    NumbArray[4]=(Number/1)    %10+0x30; 
    NumbArray[5]= 0;     
    UART_SendString(NumbArray);
}

//*********************************************************************************** 


函數名稱:UART_SendFloatNumber
函數功能:串口發送浮點型數字
//*********************************************************************************** 
void UART_SendFloatNumber(float Number)
{
    unsigned char NumberArray[11]={0};              // 定義局部數組,用於數據存儲
    unsigned char i=1;                              // 定義局部變量,記錄整數位數
    long j=1;
    unsigned int Real_Int=0;                        // 定義局部變量,記錄整數部分
    unsigned int Real_Dec=0;                        // 定義局部變量,記錄小數部分

    double Deci=0;                                  // 定義局部數組,暫存小數數值
    
    //----------------------------------------------------------------------------------------------
    // 判斷 浮點數字正負
    //----------------------------------------------------------------------------------------------
    if(Number<0)
    {
        Number=0-Number;
        UART_Sendchar('-');
    }
    else
    {
        UART_Sendchar('+');
    }

    //----------------------------------------------------------------------------------------------
    // 分離 整數位與小數位
    //----------------------------------------------------------------------------------------------
    Real_Int=(int)Number;                           // 取整數部分
    Deci    =Number-Real_Int;                       // 取小數部分
    Real_Dec=(unsigned int)(Deci*1e4);              // 小數變整型數字,1e4科學計數法


    //----------------------------------------------------------------------------------------------
    // 串口輸出
    //----------------------------------------------------------------------------------------------
    NumberArray[0] = (Real_Int/10000)%10+0x30;
    NumberArray[1] = (Real_Int/1000) %10+0x30;
    NumberArray[2] = (Real_Int/100)  %10+0x30;
    NumberArray[3] = (Real_Int/10)   %10+0x30;
    NumberArray[4] = (Real_Int/1)    %10+0x30;
    NumberArray[5] = '.';
    NumberArray[6] = (Real_Dec/1000)%10+0x30;
    NumberArray[7] = (Real_Dec/100) %10+0x30;
    NumberArray[8] = (Real_Dec/10)  %10+0x30;
    NumberArray[9] = (Real_Dec/1)   %10+0x30;
    NumberArray[10]= 0;

    UART_SendString(NumberArray);
}


/************************************************************************* 函數名稱:MAIN 函數功能:主函數 **************************************************************************/
void main()
{
	UART_init();
	while(1)
	{
		if(S4==0)
		{
			delay(20);
			if(!S4)
			{
				while(!S4);		   
				//UART_Sendchar(zifu);
				//UART_SendString("dpj");
				UART_SendString("wlb");
				UART_SendLine();
				UART_SendIntNumber(100);
			}
		}
	}
}

void uart(void) interrupt 4		 //串口發送中斷
{
	 if(RI)    //收到數據
	 {
		RI=0;   //清中斷請求
	 }
	 else      //發送完一字節數據
	 {
			TI=0;
			sending=0;  //清正在發送標志
	 }
}

在這里插入圖片描述
3. 普中單片機–串口通信(2)—通過串口助手發送數據點LED

#include <reg52.h>
#define jingzhen 12000000UL /*使用12.0M晶體*/ //
#define botelv 4800UL /*波特率定義為4800*/
 
typedef unsigned char uchar;
typedef unsigned int uint;

uchar buf;

sbit beep=P1^5;

void main(void) 
{
		 EA=0; //暫時關閉中斷
		 TMOD&=0x0F;  //定時器1模式控制在高4位
		 TMOD|=0x20;    //定時器1工作在模式2,自動重裝模式
		 SCON=0x50;     //串口工作在模式1
		 TH1=256-jingzhen/(botelv*12*16);  //計算定時器重裝值
		 TL1=256-jingzhen/(botelv*12*16);
		 PCON|=0x80;    //串口波特率加倍
		 ES=1;         //串行中斷允許
		 TR1=1;        //啟動定時器1
		 REN=1;        //允許接收 
		 EA=1;         //允許中斷
    
	  while(1);        
}
/********************************************************* 串行中斷服務函數 *********************************************************/
void  serial() interrupt 4 
{
   ES = 0;                //關閉串行中斷
   RI = 0;                //清除串行接受標志位
   buf = SBUF;            //從串口緩沖區取得數據
  switch(buf)
   {
      case 0x31:  P2=0xfe;beep=1;break;  //接受到1,第一個LED亮 
      case 0x32:  P2=0xfd;beep=1;break;  //接受到2,第二個LED亮 
      case 0x33:  P2=0xfb;beep=1;break;  //接受到3,第三個LED亮 
      case 0x34:  P2=0xf7;beep=1;break;  //接受到4,第四個LED亮 
      case 0x35:  P2=0xef;beep=1;break;  //接受到5,第五個LED亮 
      case 0x36:  P2=0xdf;beep=1;break;  //接受到5,第六個LED亮 
      case 0x37:  P2=0xbf;beep=1;break;  //接受到5,第七個LED亮
	    case 0x38:  P2=0x7f;beep=1;break;  //接受到5,第八個LED亮
	    default:    beep=0;P2=0xff;break;  //接受到其它數據,蜂鳴器響 
   }
   ES = 1;    //允許串口中斷
}
  1. HC05藍牙模塊LCD12864顯示
/*----------------------------------------------------------------------------- * 實 驗 名 : HC05藍牙模塊LCD12864顯示 * 實驗說明 : 普中單片機藍牙串口接收數據控制燈亮滅和LCD12864顯示 * 連接方式 : * 注 意 : 該試驗使用的晶振是12MHZ *******************************************************************************/
 
#include<reg52.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int
	

#define jingzhen 12000000UL /*使用12.0M晶體*/ 
#define botelv 4800UL /*波特率定義為4800*/
 
uchar PuZh[] = "www.1234567890.com";
 
//--定義使用的IO--//
 /********************************************************************************************************** 端口定義 ************************************************************************************************************/

sbit RS=P2^6; //命令/數據選擇 
sbit RW=P2^5;  //讀寫口 
sbit  E=P2^7;	  //鎖存控制 
sbit RES = P2^0; 
sbit PSB = P2^2;

sbit LED1=P2^3;
sbit LED2=P2^4;

//--聲明全局函數--// 
void UsartConfiguration();
void Delay_1ms(uint i);
void delay(unsigned int time);
void DELAY_nUS(unsigned int Time);
void DELAY_nMS(unsigned int time);
/******************************************************************** * 名稱 : Delay_1ms() * 功能 : 延時子程序,延時時間為 1ms * x * 輸入 : x (延時一毫秒的個數) * 輸出 : 無 ***********************************************************************/
void Delay_1ms(uint i)//1ms延時
{
  uchar x,j;
  
  for(j=0;j<i;j++)
    for(x=0;x<=148;x++);
}

void DELAY_nMS(unsigned int time)
{
  unsigned int  i,j;             
  for(i=0;i<time;i++)    
     for(j=0;j<939;j++); 
}

void DELAY_nUS(unsigned int Time)
{
	while(--Time);
}


void delay(unsigned int time)              //int型數據為16位,所以最大值為65535 
 {										   //0.1ms
   unsigned int  i,j;                  //定義變量i,j,用於循環語句 
   for(i=0;i<time;i++)         //for循環,循環50*time次
     for(j=0;j<50;j++);       //for循環,循環50次
 }
 
/********************************************************** LCD12864部分 *************************************************************/
 void checkbusy(void)           
{
   RS=0;                   
   RW=1;                  
   E=1;                    
   while((P0&0x80)==0x80); 
   E=0;                   
}

void wcode(unsigned char cmdcode)
{
   checkbusy();           
   RS=0;                   
   RW=0;                   
   E=1;                  
   P0=cmdcode;            
   delay(10);               
   E=0;                    
}
void wdata(unsigned char dispdata)
{
   checkbusy();           
   RS=1;                  
   RW=0;                  
   E=1;                   
   P0=dispdata;           
   delay(10);              
   E=0;                    
}


void LCD12864_InitLCD(void)
   {
		 PSB=1;            
		 RES=0;
		 delay(10);         
		 RES=1;             
		 wcode(0x30);       
		 wcode(0x0c);       
		 wcode(0x01);       
		 wcode(0x06);       	
}  

void LCD12864_Display_Char(unsigned char x,unsigned char y,unsigned char  Char)   
{                                    
  switch(y)                              
     { 
			case 0: wcode(0x80+x);break;    //第1行
	    case 1: wcode(0x90+x);break;    //第2行
	    case 2: wcode(0x88+x);break;    //第3行
	    case 3: wcode(0x98+x);break;    //第4行
      default:break;
	   }
	 wdata(Char);


}

void LCD12864_Display_String(unsigned char x,unsigned char y,unsigned char  *s)   
{                                    
 switch(y)                                     
     { 
			case 0: wcode(0x80+x);break;   
			case 1: wcode(0x90+x);break;    
			case 2: wcode(0x88+x);break;   
			case 3: wcode(0x98+x);break;    
				default:break;
	 }
   while(*s>0)                        
     {  
				wdata(*s);                     
				delay(10);                     
				s++;                         
     }
}

void LCD12864_Display_UnsignedInt(unsigned char x,unsigned char y,unsigned int Number,unsigned char Count)
{
	unsigned char NumbArray[6]={0};    
   
    NumbArray[0]=(Number/10000)%10+0x30; 
    NumbArray[1]=(Number/1000) %10+0x30;
    NumbArray[2]=(Number/100)  %10+0x30;
    NumbArray[3]=(Number/10)   %10+0x30;
    NumbArray[4]=(Number/1)    %10+0x30; 
    NumbArray[5]= 0;
 
    LCD12864_Display_String(x,y,&NumbArray[5-Count]);
}


void Display_SignedInt(unsigned char x,
                       unsigned char y,
                       signed int Number,
                       unsigned char Count)
{
    unsigned char NumberArray[7]={0};    
    signed int Number_Temp;
    
    Number_Temp = Number;
    if(Number_Temp<0)
    {
        Number_Temp = 0 - Number_Temp;
    }

    NumberArray[0]='+'; 
    NumberArray[1]=(Number_Temp/10000)%10+0x30; 
    NumberArray[2]=(Number_Temp/1000) %10+0x30;
    NumberArray[3]=(Number_Temp/100)  %10+0x30;
    NumberArray[4]=(Number_Temp/10)   %10+0x30;
    NumberArray[5]=(Number_Temp/1)    %10+0x30;
    NumberArray[6]=0;
    
    if(Number>0)
    {
        NumberArray[5-Count] = '+';
    }
    else
    {
        NumberArray[5-Count] = '-';
    }
    
    LCD12864_Display_String(x, y, &NumberArray[5-Count]);
}


 
/******************************************************************** * 名稱 : Com_Int() * 功能 : 串口中斷子函數 * 輸入 : 無 * 輸出 : 無 ***********************************************************************/
void Com_Int(void) interrupt 4
{
	uchar i;
  uchar receive_data;
	
  EA = 0;
	
  if(RI == 1) //當硬件接收到一個數據時,RI會置位
	{ 		
			RI = 0;
			receive_data = SBUF;//接收到的數據
			
		if(receive_data == '1')	 
		{
				LED1=0;
			  DELAY_nMS(200);
			  LED1=1;
			  DELAY_nMS(200);
			  LCD12864_Display_String(0,1,"led1");
			  DELAY_nMS(500);
			  wcode(0x01);
				LED2=1;
			  DELAY_nMS(200);
			  LED2=0;
			  DELAY_nMS(200);
			  LCD12864_Display_String(0,2,"led2");
			  DELAY_nMS(500);
			  wcode(0x01);
		}
		else if(receive_data == '2')	 
		{
			  LED2=1;
			  DELAY_nMS(200);
			  LED2=0;
			  DELAY_nMS(200);
			  LCD12864_Display_String(8,2,"led2");
			  DELAY_nMS(500);
			  wcode(0x01);
				LED1=0;
			  DELAY_nMS(200);
			  LED1=1;
			  DELAY_nMS(200);
			  LCD12864_Display_String(8,1,"led1");
			  DELAY_nMS(500);
			  wcode(0x01);
			  
				
		}
		else 
		{
			 LCD12864_Display_String(0,3,"error");
			 DELAY_nMS(500);
			 wcode(0x01);
		}
		
	}
		
		for(i=0; i<36; i++)
		{
			SBUF = PuZh[i];   //將要發送的數據放入到發送寄存器
			while(!TI);		    //等待發送數據完成
			TI=0;			        //清除發送完成標志位
			Delay_1ms(1);
		}
		EA = 1;
}

/******************************************************************************* * 函 數 名 : UsartConfiguration() * 函數功能 : 設置串口 * 輸 入 : 無 * 輸 出 : 無 *******************************************************************************/


void  UsartConfiguration(void)				//串口初始化
{
		 EA=0;            //暫時關閉中斷
		 TMOD&=0x0F;      //定時器1模式控制在高4位
		 TMOD|=0x20;      //定時器1工作在模式2,自動重裝模式
		 SCON=0x50;       //串口工作在模式1
		 TH1=256-jingzhen/(botelv*12*16);  //計算定時器重裝值
		 TL1=256-jingzhen/(botelv*12*16);
		 PCON|=0x80;    //串口波特率加倍
		 ES=1;         //串行中斷允許
		 TR1=1;        //啟動定時器1
		 REN=1;        //允許接收 
		 EA=1;         //允許中斷
}
 
/******************************************************************************* * 函 數 名 : main * 函數功能 : 主函數 * 輸 入 : 無 * 輸 出 : 無 *******************************************************************************/ 
void main()
{
 
	UsartConfiguration();//初始化串口
	LCD12864_InitLCD();
	//LCD12864_Display_String(0,1,"test");
	while(1)
	{
		//LCD12864_Display_String(0,0,"test");
	}
}

參考資料

普中科技–普中單片機開發資料
蒙蒙Plus–一周學習完51單片機
海創電子–51單片機學習


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM