文章目錄

  • 如何創建 Keil 工程
  • 創建步驟
  • 1. 創建文件夾結構
  • 2. 打開 Keil
  • 3. 創建新工程
  • 4. 創建不同類型的內容
  • 頭文件
  • 明白頭文件包含了什麼
  • 標題具體內容
  • sfr
  • sbit
  • bit
  • 延時函數(模塊化)
  • delay.c
  • delay.h
  • 外部中斷
  • 一、初始化配置
  • 二、編寫中斷服務函數
  • 關於定時器
  • 一、初始化定時器
  • 二、編寫中斷服務函數
  • 模式一
  • 模式二
  • 三、啓動定時器
  • 關於中斷與段號
  • 中斷注意
  • 串口通信
  • 核心**通信參數**(“波特率” 是關鍵)
  • 數據低位先發(對於串口)
  • 擴展
  • 進行模塊化
  • 錯誤與警告

如何創建 Keil 工程

創建步驟

1. 創建文件夾結構

  • 先創建一個文件夾 code 保存你寫的所有文件
  • 創建一個按照工程目的命名的文件夾

2. 打開 Keil

  • 打開 Keil 軟件

3. 創建新工程

  • 依據圖中選擇相應選項
  • 51單片機學習——1天學完普中基本實驗例程,走馬觀花式學習,大家切勿效仿。_小輝_Super的博客-博客_數據

  • 選擇第二步創建的文件夾
  • 將文件命名為 project(我一般這樣命名)

4. 創建不同類型的內容

如創建 .c 文件:

第一步

51單片機學習——1天學完普中基本實驗例程,走馬觀花式學習,大家切勿效仿。_小輝_Super的博客-博客_初始化_02

第二步

51單片機學習——1天學完普中基本實驗例程,走馬觀花式學習,大家切勿效仿。_小輝_Super的博客-博客_初值_03

頭文件

明白頭文件包含了什麼

頭文件包含了該系列單片機的特殊功能寄存器(SFR)定義、位定義以及部分常用常量的聲明。

標題具體內容

右鍵點擊頭文件名(如 reg52.h),在彈出的菜單中選擇 Open document “reg52.h”
或直接 按住 Ctrl 鍵,用鼠標左鍵點擊頭文件名,即可直接打開該頭文件。

sfr

(Special Function Register)
語法:
語法:sfr 寄存器名 = 地址;

sbit

(Special Bit)
語法:
① sbit 位名 = 寄存器名^位號;

② sbit 位名 = 位地址;

類似於一個標籤,如果用 sbit key = P1^2; 表示的就是在後續使用中,key 可以代表 P1 口的第 3 位,也可以用 sbit key = P1.2; 表示。

bit

一個特殊的數據類型,用於定義位變量。

取值範圍:只能是 0(假)或 1(真)

注意

bit 是 Keil C51 編譯器的擴展類型,並非標準 C 語言的一部分

主要用於 8051 單片機編程

示例:

bit flag;       // 定義一個位變量flag
bit led_state;  // 定義一個表示LED狀態的位變量

延時函數(模塊化)

delay.c

#include "reg52.h"
// 假設使用11.0592MHz晶振,STC89C52RC單片機
// 此函數由STC-ISP延時函數生成器生成
/**
* @brief 微秒級延時函數
* @param us 延時微秒數,範圍:0~65535
*/
void delay_us(unsigned int us)
{
unsigned int i;
while(us--)
{
i = 2;
while(i--);
}
}
/**
* @brief 毫秒級延時函數
* @param ms 延時毫秒數,範圍:0~65535
*/
void delay_ms(unsigned int ms)
{
unsigned int i, j;
for(i = 0; i < ms; i++)
for(j = 0; j < 112; j++);  // 11.0592MHz下約1ms的循環
}

delay.h

#ifndef __DELAY_H__
#define __DELAY_H__
// 函數聲明
void delay_ms(unsigned int ms);  // 毫秒級延時
void delay_us(unsigned int us);  // 微秒級延時
#endif


外部中斷

初始化配置→編寫中斷服務函數 → 中斷觸發與執行

一、初始化配置

  • EA:總中斷允許位(=1 允許總中斷)
  • EX0:INT0 中斷允許位(P3.2
  • EX1:INT1 中斷允許位(P3.3
void External0_Init(void) {
    IT0 = 1;  // 設置INT0為下降沿觸發方式
    EX0 = 1;  // 使能INT0中斷
    EA = 1;   // 開總中斷
}

觸發方式選擇(IT0 = 0 低電平觸發,= 1 下降沿觸發)如果不進行選擇的話就是 低電平觸發

二、編寫中斷服務函數

void External0_ISR(void) interrupt 0 {
// 假設連接在P2.0引腳的LED,每次中斷翻轉其狀態
P2 ^= 0x01;
}

外部中斷函數後綴是INT0 interrupt 0

注意INT1 中斷的中斷號是 2(interrupt 2

關於定時器

初始化定時器 → 編寫中斷服務函數 → 啓動定時器

一、初始化定時器

使用 TMOD 寄存器設置工作模式

常用模式:

模式 1:16 位定時器 / 計數器

模式 2:8 位自動重裝載

模式比較

51單片機學習——1天學完普中基本實驗例程,走馬觀花式學習,大家切勿效仿。_小輝_Super的博客-博客_數據_04

根據晶振頻率和所需定時時間計算初值
裝入 THx 和 TLx 寄存器

開總中斷:EA = 1
開定時器中斷:ETx = 1
設置優先級 (可選):PTx = 0/1

二、編寫中斷服務函數

模式一

  • T:想要的定時時間(單位:秒)
  • fosc:晶振頻率(單位:Hz)
  • 12:因為 51 單片機默認每個機器週期 = 12 個時鐘週期
    定時時間公式:T = (2^N - 初值) × 12 /fosc

模式 1 (16 位) 初值計算:

初值 = 65536 - (T × fosc) / 12

示例:晶振 12MHz,定時 50ms

初值 = 65536 - (50000 × 12000000) / 12 = 15536
TH0 = 15536 / 256;
TL0 = 15536 % 256;
void Timer0_ISR(void) interrupt 1 {
// 1. 重裝載初值(模式1需要)
TH0 = (65536 - 初值) / 256;
TL0 = (65536 - 初值) % 256;
// 2. 執行定時任務
// ...
// 3. 設置標誌位(可選)
timer_flag = 1;
}

模式二

自動重裝載(8位)

8位模式下,初值高八位和低八位相同,即TH0=TL0=初值

51單片機學習——1天學完普中基本實驗例程,走馬觀花式學習,大家切勿效仿。_小輝_Super的博客-博客_初始化_05

// 定時器0初始化函數
void Timer0_Init(void) {
TMOD &= 0xF0;   // 清除定時器0的模式(低4位)
TMOD |= 0x02;   // 配置定時器0為模式2(8位自動重裝載)
TH0 = 156;      // 設置自動重裝載的初值(高8位)
TL0 = 156;      // 設置初始計數的初值(低8位)
ET0 = 1;        // 使能定時器0中斷
EA = 1;         // 使能總中斷
TR0 = 1;        // 啓動定時器0
}

三、啓動定時器

TRx = 1;  // 啓動定時器

關於中斷與段號

51單片機學習——1天學完普中基本實驗例程,走馬觀花式學習,大家切勿效仿。_小輝_Super的博客-博客_初始化_06

中斷注意

“中斷內部不能執行時間超過 100ms,否則循環不能完成”

核心邏輯:中斷的高優先級會搶佔 CPU,若 ISR 耗時過長,會導致主循環 / 關鍵任務 “得不到 CPU 資源”,要麼被頻繁打斷無法推進,要麼因中斷延遲 / 丟失導致數據異常,最終表現為 “循環不能完成”。

串口通信

什麼是串口

串口對應的就是並口

要傳遞信息,兩器件之間需要共地

核心通信參數(“波特率” 是關鍵)

串口通信前,收發雙方必須約定好以下 4 個參數(參數不匹配會導致通信失敗):

波特率(Baud Rate):數據傳輸的 “速度”,單位是 bps(bit per second,每秒傳輸的 bit 數)。常見值:9600bps、115200bps(最常用,約 11.5KB/s)、460800bps。類比:波特率就像 “説話速度”,雙方必須語速一致,否則一方説太快,另一方聽不清。
數據位(Data Bits):每次傳輸的 “有效數據位數”,通常是 8 位(1 個字節)。比如要傳字符 “a”(ASCII 碼 0x61,二進制 01100001),就用 8 位數據位傳輸。
停止位(Stop Bits):每傳輸完一個 “數據幀” 後,加 1~2 個 bit 的 “停止位”,用於標識 “一幀數據結束”。常見值:1 位停止位(默認)、2 位停止位(用於傳輸可靠性要求高的場景,如工業控制)。
校驗位(Parity Bit):可選參數,用於 “檢查數據是否傳錯”(糾錯機制)。常見類型:無校驗(None,最常用)、奇校驗(Odd)、偶校驗(Even)。比如 8 位數據位 + 奇校驗:8 個數據 bit 的 “1” 的個數是偶數,就加 1 個 “1” 使總個數為奇數;若傳輸後 “1” 的個數不對,説明數據出錯。

數據低位先發(對於串口)

舉例

如果數據是0x55(0101 0101)

那麼在波形圖中顯示應該是 1010 1010(從小往大看)

擴展

代碼流程
硬件初始化 → 發送數據 → 接收數據

初始化流程(以方式 1 為例)
方式 1 是最常用的:8 位異步通信波特率可變(由定時器 1 溢出率決定)。

1、初始化步驟
設置 SCON:

  1. SM0 = 0, SM1 = 1 → 方式 1
  2. REN = 1 → 允許接收
  3. 其餘位(SM2、TB8、RB8)可置 0
SCON = 0x50;  // 0101 0000

2、設置波特率(用定時器 1,方式 2 自動重載):

  1. 晶振頻率 fosc 已知(如 11.0592MHz)
  2. 波特率公式:(波特率 = \frac{2^{SMOD}}{32} \times
    \frac{fosc}{12 \times (256 - TH1)})
  3. 例:波特率
    9600,fosc=11.0592MHz,SMOD=0:(TH1 = 256 - \frac{fosc}{32 \times 12
    \times 波特率})(TH1 = 256 - \frac{11059200}{32 \times 12 \times 9600}
    = 0xFD)
TMOD |= 0x20; // 定時器1 方式2
TH1 = 0xFD;   // 波特率9600
TL1 = 0xFD;
TR1 = 1;      // 啓動定時器1

開啓中斷(可以選擇):

ES = 1; // 串口中斷允許
EA = 1; // 總中斷允許
  1. 發送數據流程
    (1)查詢方式
void UartSendByte(unsigned char dat)
{
SBUF = dat;       // 寫入要發送的數據
while(TI == 0);   // 等待發送完成
TI = 0;           // 軟件清零發送標誌
}
void UartSendString(unsigned char *str)
{
while(*str)
{
UartSendByte(*str++);
}
}

(2)中斷方式

unsigned char sendBuf[100];
unsigned int sendLen = 0;
unsigned int sendIndex = 0;
void UartSendString_IT(unsigned char *str)
{
sendLen = 0;
while(str[sendLen]) sendLen++;
sendIndex = 0;
SBUF = str[sendIndex++]; // 先發第一個字節
TI = 0;
ES = 1; // 允許串口中斷
}
void UartIsr(void) interrupt 4
{
if(TI)  // 發送中斷
{
TI = 0;
if(sendIndex < sendLen)
{
SBUF = sendBuf[sendIndex++];
}
else
{
ES = 0; // 發送完成,關閉中斷
}
}
if(RI)  // 接收中斷
{
RI = 0;
// 處理接收數據
}
}
  1. 接收數據流程
    (1)查詢方式
unsigned char UartRecvByte(void)
{
while(RI == 0); // 等待接收完成
RI = 0;         // 清標誌
return SBUF;    // 返回接收到的數據
}

(2)中斷方式

unsigned char recvByte;
void UartIsr(void) interrupt 4
{
if(RI)
{
RI = 0;
recvByte = SBUF; // 讀取數據
// 在這裏處理接收到的數據
}
}


進行模塊化

單獨創建一個文件夾儲存模塊化文件

.c和.h,當需要是複製到相關文件夾下,在將其添加到列表

51單片機學習——1天學完普中基本實驗例程,走馬觀花式學習,大家切勿效仿。_小輝_Super的博客-博客_初值_07

注意!!!!

一定要看是不是在一個路徑下面,否則很有可能找不到相關文件

51單片機學習——1天學完普中基本實驗例程,走馬觀花式學習,大家切勿效仿。_小輝_Super的博客-博客_初值_08



錯誤與警告


51單片機學習——1天學完普中基本實驗例程,走馬觀花式學習,大家切勿效仿。_小輝_Super的博客-博客_數據_09

有函數未被調用
WARNING LI6: UNCALLED SEGMENT, IGNORED FOR OVERLAY PROCESS

面對類似警告,是因為有的函數未被調用,可以不用理會,忽略就好了