STC89C52RC
- 芯片手冊
- 原理圖
- 擴展版原理圖
- 功能示例
- LED燈
- ==LED燈的常亮效果==
- ==LED燈的閃爍==
- ==LED燈的跑馬燈效果:從左到右,從右到左==
- 數碼管
- 靜態數碼管
- 數碼管計數
- mian.c
- App.c
- App.h
- Com.c
- Com.h
- Dir.c
- Dir.h
- Int.c
- Int.h
- Mid.c
- Mid.h
- 模板
- mian.c
- App.c
- App.h
- Com.c
- Com.h
- Dir.c
- Dir.h
- Int.c
- Int.h
- Mid.c
- Mid.h
芯片手冊
STC89C52
原理圖
擴展版原理圖
擴展版原理圖
功能示例
LED燈
LED燈的常亮效果
# include <STC89C5xRC.H>
void main(){//將LED連接的P00端口設置為0P00 =0;while(1);
}
LED燈的閃爍
/*----------------------------------------------------------* 文件名:LED_FlowLight.c* 功能:STC89C52RC單片機控制的LED流水燈程序(單向左移循環)* 硬件連接:P0口接8個共陽LED,P4.6控制蜂鳴器* 作者:[您的名字]* 日期:[創建日期]*---------------------------------------------------------*/#include <STC89C5xRC.H> // 包含STC89C52RC系列單片機寄存器定義頭文件
#include <INTRINS.H> // 包含內部函數庫(提供_nop_()空指令)/* 類型重定義(增強可讀性)*/
typedef unsigned char u8; // 定義無符號8位數據類型(范圍0~255)
typedef unsigned int u16; // 定義無符號16位數據類型(范圍0~65535)/* 函數聲明 */
void Delayms(u16 count); // 毫秒級延時函數聲明/*----------------------------------------------------------* 主函數*---------------------------------------------------------*/
void main()
{// 變量初始化u8 temp = 0x01; // 初始化LED位置(二進制00000001,對應最右側LED)// 注:實際是P0.0對應第一個LED,P0.7對應第八個LEDP46 = 0; // 關閉蜂鳴器(硬件設計缺陷,P4.6低電平關閉蜂鳴器)// 如果不設置,上電時可能產生噪音while (1) // 主循環(單片機程序必須包含無限循環){/* LED顯示控制 */P0 = ~temp; // 輸出到P0口控制LED:// - 取反操作是因為采用共陽接法(端口輸出0時LED亮)// - 例如temp=0x01(00000001),取反后=0xFE(11111110),// 即P0.0輸出0,對應LED點亮/* 更新LED位置 */temp <<= 1; // 左移一位,實現LED流水效果// 例如:0x01→0x02→0x04→...→0x80/* 循環檢測 */if (temp == 0) // 當左移超出8位時(0x80<<1會變成0x00){temp = 0x01; // 重新從最右側開始}/* 延時控制流水速度 */Delayms(100); // 延時100ms(控制LED移動速度)}
}/*----------------------------------------------------------* 函數名稱:Delayms* 功能:實現毫秒級延時* 參數:count - 需要延時的毫秒數* 說明:針對12MHz晶振校準,其他頻率需調整參數*---------------------------------------------------------*/
void Delayms(u16 count)
{/* 變量定義(使用data關鍵字將變量存儲在內部RAM,提高訪問速度)*/u8 data i, j; while (count--) // 外層循環(控制總延時毫秒數){_nop_(); // 空指令(消耗1個機器周期,12MHz下=1us)// 用于微調延時精度/* 雙重循環實現精確延時 */i = 2;j = 199;do{while (--j); // 內層循環1(約199×3個機器周期)} while (--i); // 內層循環2(外層循環2次)/* * 延時計算(12MHz時鐘):* - 1機器周期=1us* - 內層循環:199×3 = 597us* - 外層循環:2×597 = 1194us ≈ 1ms* - 總延時:count × 1ms*/}
}
LED燈的跑馬燈效果:從左到右,從右到左
#include <STC89C5xRC.H> // 包含STC89C52RC系列單片機頭文件
#include <INTRINS.H> // 包含 intrinsics 函數(如_nop_)typedef unsigned char u8; // 定義無符號8位數據類型(0~255)
typedef unsigned int u16; // 定義無符號16位數據類型(0~65535)// 函數聲明
void Delayms(u16 count); // 毫秒級延時函數聲明void main()
{// 變量初始化u8 temp = 0x01; // 初始燈位(00000001,最右側LED亮)bit is_left = 1; // 方向標志(1=左移,0=右移)while (1) // 主循環{P0 = ~temp; // 輸出到P0口(取反因為LED共陽接法)// 根據移動方向更新燈位if (is_left) {temp <<= 1; // 左移一位(LED向左移動)} else {temp >>= 1; // 右移一位(LED向右移動)}// 檢測邊界條件并改變方向if (temp == 0x80) { // 當移動到最左端(10000000)is_left = 0; // 改為右移方向}if (temp == 0x01) { // 當移動到最右端(00000001)is_left = 1; // 改為左移方向}Delayms(100); // 延時100ms控制移動速度}
}/*** @brief 毫秒級延時函數* @param count 延時毫秒數* @note 針對12MHz晶振校準,其他頻率需要調整參數*/
void Delayms(u16 count)
{u8 data i, j; // 使用data關鍵字將變量存儲在內部RAMwhile (count--) // 外層循環(毫秒級){_nop_(); // 空指令(4個時鐘周期)i = 2;j = 199;do // 內層循環(微秒級){while (--j); // 約100us} while (--i); // 組合成約1ms延時}
}
數碼管
靜態數碼管
#include <STC89C5xRC.H> // 包含STC89C52RC系列單片機頭文件
#include <INTRINS.H> // 包含 intrinsics 函數(如_nop_)typedef unsigned char u8; // 定義無符號8位數據類型
typedef unsigned int u16; // 定義無符號16位數據類型
typedef unsigned long u32; // 定義無符號32位數據類型// 函數聲明
void DigitalTube_setBuffer(u32 number); // 設置數碼管顯示緩沖區
void DigitalTube_Single(u8 pos, u8 number); // 控制單個數碼管顯示
void DigitalTube_Refresh(); // 刷新整個數碼管顯示
static void Delayms(u16 count); // 毫秒級延時函數(static限制作用域)// 數碼管段選碼(共陰數碼管0-9,對應a~dp段)
// 編碼格式:gfedcba(P0.0~P0.6),最高位P0.7為小數點
const u8 number_codes[10] = {0x3F, // 0 - 001111110x06, // 1 - 000001100x5B, // 2 - 010110110x4F, // 3 - 010011110x66, // 4 - 011001100x6D, // 5 - 011011010x7D, // 6 - 011111010x07, // 7 - 000001110x7F, // 8 - 011111110x6F // 9 - 01101111
};u8 digital_buffer[8]; // 數碼管顯示緩沖區(存儲8位數碼管的段選值)void main()
{// 初始化IO口// P0 = 0x00; // 段選初始化為全滅(注釋掉,實際在刷新函數中處理)// P1 = 0xC7; // 位選初始化為全滅(P1.3-P1.5控制位選,11000111)P46 = 0; // 可能的總使能信號(低電平有效)P36 = 0; // 數碼管使能信號(低電平有效)P34 = 1; // 關閉流水燈(高電平關閉)DigitalTube_setBuffer(99998888); // 設置初始顯示值為250while (1){DigitalTube_Refresh(); // 持續刷新數碼管顯示}
}/*** @brief 設置數碼管顯示緩沖區內容* @param number 要顯示的數字(最大支持8位數)* @note 數字將右對齊顯示,不顯示前導零*/
void DigitalTube_setBuffer(u32 number)
{u8 i;// 1. 清空緩沖區(全部顯示空白)for (i = 0; i < 8; i++) {digital_buffer[i] = 0; // 0表示不顯示任何段}// 2. 從最右側開始填充數字(右對齊)for (i = 7; i >= 0; i--) {digital_buffer[i] = number_codes[number % 10]; // 獲取當前位的段碼number /= 10; // 移除已處理的最低位if (number == 0) break; // 數字已處理完畢則退出}
}/*** @brief 控制單個數碼管顯示* @param pos 數碼管位置(0-7對應位選)* @param number 要顯示的段碼值* @note 使用P1.3-P1.5控制3-8譯碼器選擇位選*/
void DigitalTube_Single(u8 pos, u8 number)
{// 1. 位選控制(通過P1.3-P1.5)pos <<= 3; // 左移3位,將0-7映射到P1.3-P1.5P1 &= 0xC7; // 11000111 - 清除位選位(P1.3-P1.5)P1 |= pos; // 設置新的位選// 2. 段選輸出P0 = number; // 輸出段碼值到P0口
}/*** @brief 刷新整個數碼管顯示(動態掃描)* @note 采用循環掃描方式,每位顯示1ms*/
void DigitalTube_Refresh()
{u8 i = 0;while (i <= 7) // 掃描0-7共8位數碼管{DigitalTube_Single(i, digital_buffer[i]); // 顯示當前位Delayms(1); // 保持顯示1msi++;}
}/*** @brief 毫秒級延時函數* @param count 延時毫秒數* @note 使用static限制只在本文件使用,防止命名沖突*/
static void Delayms(u16 count)
{u8 data i, j;while (count--){_nop_(); // 空指令,用于精確延時i = 2;j = 199;do{while (--j); // 內層循環延時} while (--i); // 外層循環延時}
}
數碼管計數
mian.c
#include ".\Com\Com_Util.h"
#include ".\Int\Int_DigitalTube.h"// 主函數
void main()
{u8 num = 100;u8 count = 0;u8 i=0;P46 = 0; // 關閉蜂鳴器// 初始化數碼管Int_DigitalTube_Init();//設置要顯示的數字Int_DigitalTube_setBuffer(num);//死循環while (1){Int_DigitalTube_setBuffer(num);while (count <= 100){Int_DigitalTube_Refresh();count++;}if (num > 0){num--;count=0;}else if (num == 0){while (1){Int_DigitalTube_setBuffer(0);}}}
}
App.c
App.h
Com.c
#include "Com_Util.h"// 延時函數,指定延時多少毫秒
void Delayms(u16 count)
{u8 data i, j;while (count){_nop_();i = 2;j = 199;do{while (--j);} while (--i);count--;}
}
Com.h
#ifndef __COM_UTIL_H__
#define __COM_UTIL_H__#include <STC89C5xRC.H>
#include <INTRINS.H>// 類型別名
typedef unsigned char u8;
typedef unsigned int u16;
typedef unsigned long u32;/*** @brief 延時函數,指定延時多少毫秒** @param count 指定多少毫秒*/
void Delayms(u16 count);#endif
Dir.c
Dir.h
Int.c
#include "Int_DigitalTube.h"// 定義數組,保存每個數字的段選信息
static u8 s_number_codes[10] = {0x3F, // 00x06, // 10x5B, // 20x4F, // 30x66, // 40x6D, // 50x7D, // 60x07, // 70x7F, // 80x6F // 9
};// 定義數組,8個元素,對應數碼管8個位置; 每個元素存儲數字的段選信息
static u8 s_digital_buffer[8];/*** @brief 數碼管初始化*/
void Int_DigitalTube_Init()
{// 打開數碼管開關P36 = 0;// 關閉流水燈P34 = 0;
}/*** @brief 將指定的整數設置到數碼管顯示緩存中(s_digital_buffer數組)** @param number*/
void Int_DigitalTube_setBuffer(u32 number)
{u8 i;// 1. 清空之前的顯示內容for (i = 0; i < 8; i++){s_digital_buffer[i] = 0x00;}// 2. 依次取出number中每位上的數,將其段選信息存儲數組;最低位存入最后一個元素for (i = 7;; i--){// 取出當前位上的數,將其段選信息存入數組指定位置s_digital_buffer[i] = s_number_codes[number % 10];// 處理number,去掉最低位number /= 10;// 如果number變為0,說明數字已經取完,停止循環if (number == 0 || i == 0){break;}}
}/*** @brief 數碼管指定位置指定數字** @param pos 位置,使用數字0~7分別表示從左邊數第1到到第8個* @param code 數字的段選信息*/
void Int_DigitalTube_Single(u8 pos, u8 number_code)
{// 1. 位選 -------------------------------// 1.1 pos 左移3位, 與P15、P14、P13 對齊pos <<= 3;// 1.2 將P1的P15、P14、P13三位置0,其他位保持不變, P1 & 0b11000111P1 &= 0xC7;// 1.3 將pos上的三位有效數, 賦值到 P15、P14、P13 位置上P1 |= pos;// 2. 段選 --------------------------------P0 = number_code;
}/*** @brief 刷新數碼管**/
void Int_DigitalTube_Refresh()
{// 循環0到7u8 i;for (i = 0; i <= 7; i++){Int_DigitalTube_Single(i, s_digital_buffer[i]);Delayms(1);}
}
Int.h
#ifndef __INT_DIGITALTUBE_H__
#define __INT_DIGITALTUBE_H__#include "..\Com\Com_Util.h"/*** @brief 數碼管初始化*/
void Int_DigitalTube_Init();/*** @brief 將指定的整數設置到數碼管顯示緩存中(digital_buffer數組)* * @param number */
void Int_DigitalTube_setBuffer(u32 number);/*** @brief 數碼管指定位置指定數字** @param pos 位置,使用數字0~7分別表示從左邊數第1到到第8個* @param code 數字的段選信息*/
void Int_DigitalTube_Single(u8 pos, u8 number_code);/*** @brief 刷新數碼管**/
void Int_DigitalTube_Refresh();#endif