51單片機學習

来源:https://www.cnblogs.com/TomDing/archive/2018/05/19/9060181.html
-Advertisement-
Play Games

51單片機學習 一直想給女兒做一個平衡小車玩具,想用PLC做,感覺難度,用單片機吧,都快20年沒用了。 最近考試考完了,時間和資源都有,正好可以搗鼓一下。看了郭天翔的視頻,講的很不錯, 邊學邊寫。 定時器使用 控制任務: P1.0 控制一個LED燈,亮0.5s,滅0.5s。 設計思路:這裡我們只用定 ...


51單片機學習

一直想給女兒做一個平衡小車玩具,想用PLC做,感覺難度,用單片機吧,都快20年沒用了。
最近考試考完了,時間和資源都有,正好可以搗鼓一下。看了郭天翔的視頻,講的很不錯,
邊學邊寫。

定時器使用

控制任務:

P1.0 控制一個LED燈,亮0.5s,滅0.5s。

設計思路:這裡我們只用定時器,不用軟延時。51的定時器最多定時60ms,所以我們設置定時器每
50ms中斷一次,通過在中斷程式設置一個變數來統計中斷次數,從而實現較長時間的定時。這裡我們
是每500ms執行一次燈亮燈滅的動作,所以每10個中斷等於500ms(50ms x 10)。第6行,全局變數
timer50msCount 就是中斷次數。第19-23行,當timer50msCount 為10時,代表500ms時間到,把
P1.0 取反,動作一次。

這裡有個繁瑣的地方,定時器的初值需要手工計算。不過前人開發了一下小程式,直接拿過來用就可以了。
見下圖。把自動生成代碼中的第一行刪掉就可以了。

程式如下:

#include <reg52.h>
typedef unsigned int uint;
typedef unsigned char uchar;

sbit P10 = P1 ^ 0;
// 第 6 行
uchar timer50msCount = 0;   

void Timer0Init(void);

void main()
{
    EA = 1;         // 開總中斷
    ET0 = 1;        // 開定時器 0 中斷
    Timer0Init();

    while (1)
    {
        // 每500ms允許if語句塊中的程式
        // 19 - 23 行
        if (timer50msCount == 10)
        {
            timer50msCount = 0;
            P10 = ~P10;
        }
    }
}

void Timer0Init(void) //[email protected]
{
    TMOD &= 0xF0; // 設置定時器模式,這裡為T0
    TMOD |= 0x01; // 設置定時器工作方式1,為16為定時器
    TL0 = 0x00;   // 設置定時器低位初值
    TH0 = 0x4C;   // 設置定時器高位初值
    TF0 = 0;      // 清楚TF0溢出標誌位
    TR0 = 1;      // 啟動定時器0開始計時
}


// 定時器0中斷子程式
void timer0Interrupt() interrupt 1
{
    timer50msCount++;
    // 每次中斷時,定時器初值為0,需重新設置定時器初值,保持50ms
    // 時間不變
    TL0 = 0x00;
    TH0 = 0x4C;
}

獨立鍵盤

控制任務:

按下 s2 鍵,led 燈亮,鬆手燈滅。

見面的程式用到一個10ms的延時函數,可以用軟體自動生成,見下圖。
圖片選了1ms,和10ms的延時函數是不一致。1ms的程式里包含了_nop()_指令,
使用這條指令,需要在在代碼中使用頭文件intrins.h。

#include <intrins.h>

程式如下:

#include <reg52.h>

typedef unsigned int uint;
typedef unsigned char uchar;

sbit wela = P2 ^ 7;
sbit dula = P2 ^ 6;
sbit s2 = P3 ^ 4;       // s2 按鍵
sbit d1 = P1 ^ 0;      //  led 燈

uchar code table[] = {
    0x3f, 0x06, 0x5b, 0x4f,
    0x66, 0x6d, 0x7d, 0x07,
    0x7f, 0x6f, 0x77, 0x7c,
    0x39, 0x5e, 0x79, 0x71};

uchar code welaTable[] = {
    0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf};

void Delay10ms();

void main()
{
    uchar num = 0;
    wela = 1;
    P0 = 0xfe;
    wela = 0;

    // 把P3口置高電平
    P3 = 0xff;
    while (1)
    {
        // s2 == 0, 表示 s2 變為低電平,此時按鍵按下
        if (s2 == 0)
        {
            Delay10ms();  // 去按下時的抖動
            if (s2 == 0)
            {
                d1 = 0;  // 點亮led
                num++;   // 按鍵次數計數
                if (num > 9)  // led 數位管計數最大為9, 超出置為0
                {
                    num = 0;
                }
            }
            
            // 按鍵從按下到釋放,時間有100-200ms,單片機的
            // 掃描時間很快,此處防止鍵盤按的過程中,num值反覆加
            while (!s2)
                ;
            // 鍵盤鬆手是去毛刺延時
            Delay10ms();
        }
        else
        {
            d1 = 1;
        }

        dula = 1;
        P0 = table[num];
        dula = 0;
    }
}

void Delay10ms() //@11.0592MHz
{
    unsigned char i, j;

    i = 18;
    j = 235;
    do
    {
        while (--j)
            ;
    } while (--i);
}

矩陣鍵盤

控制任務:

4 x 4 的矩陣鍵盤,按下第0個鍵,6個數位管都顯示0,按下第一個鍵,6個數位管顯示1,一次類推。

程式如下:

#include <reg52.h>

typedef unsigned int uint;
typedef unsigned char uchar;

sbit wela = P2 ^ 7;
sbit dula = P2 ^ 6;

// 數字碼表,數字最後個0x00為不顯示.
uchar code numberTable[] = {
    0x3f, 0x06, 0x5b, 0x4f,
    0x66, 0x6d, 0x7d, 0x07,
    0x7f, 0x6f, 0x77, 0x7c,
    0x39, 0x5e, 0x79, 0x71,
    0x00};

// 行掃描編碼表, 每個元素代表一行
uchar code keyTable[] = {
    0xfe, 0xfd, 0xfb, 0xf7};

void delay10ms();
uchar keyScan();
void show(uchar num);

// 51的c編譯器比較原始,函數中返回的值只能用
// 全局變數
uchar num = 16;

void main()
{
    // 此處傳入16,數字碼表選擇0x00,
    // 上電時關閉數位管,防止顯示亂碼, 
    show(16);

    wela = 1;
    P0 = 0xc0;
    wela = 0;

    while (1)
    {
        // keyScan函數返回 0 - 15 數字
        uchar keyNum = keyScan();
        show(keyNum);
    }
}

uchar keyScan()
{

    // 鍵盤為4X4的鍵盤矩陣,每個for迴圈掃描一行,while迴圈中掃描列,
    // num變數返回這個鍵盤矩陣的鍵位,
    // 比如第0個鍵按下,返回0,第一個返回1,以此類推
    uchar i = 0, temp;
    for (; i < 4; i++)
    {
        P3 = keyTable[i];
        temp = P3 & 0xf0;
        while (temp != 0xf0)
        {
            delay10ms();
            temp = P3 & 0xf0;
            switch (temp)
            {
            case 0xe0:
                num = 4 * i + 0;
                break;
            case 0xd0:
                num = 4 * i + 1;
                break;
            case 0xb0:
                num = 4 * i + 2;
                break;
            case 0x70:
                num = 4 * i + 3;
                break;
            }
        }
    }
    return num;
}

void show(uchar num2)
{
    dula = 1;
    P0 = numberTable[num2];
    dula = 0;
}

void delay10ms() //@11.0592MHz
{
    unsigned char i, j;

    i = 18;
    j = 235;
    do
    {
        while (--j)
            ;
    } while (--i);
}

動態顯示

控制任務:

在六個數位管上分別顯示1,2,3,4,5,6

程式如下:

#include <reg52.h>

typedef unsigned int uint;
typedef unsigned char uchar;

sbit wela = P2 ^ 7;
sbit dula = P2 ^ 6;

// 段碼表
uchar code table[] = {
    0x3f, 0x06, 0x5b, 0x4f,
    0x66, 0x6d, 0x7d, 0x07,
    0x7f, 0x6f, 0x77, 0x7c,
    0x39, 0x5e, 0x79, 0x71};

// 位碼表
uchar code welaTable[] = {
    0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf};

void Delay1ms();

void main()
{
    uchar i;

    while (1)
    {
        // 依次只顯示一個數位管,但因速度很快,
        // 從而造成眼睛的錯覺
        for (i = 0; i < 6; i++)
        {
            P0 = 0xFF;  // 消影
            wela = 1;
            P0 = welaTable[i];
            wela = 0;
            dula = 1;
            P0 = table[i + 1];
            dula = 0;
            Delay1ms();  // 務必要加延時
        }
    }
}

void Delay1ms() //@11.0592MHz
{
    unsigned char i, j;

    i = 2;
    j = 199;
    do
    {
        while (--j)
            ;
    } while (--i);
}

AD 轉換

/************************
 *  通過AD晶元把模擬量電壓值轉換為數字量 *
 *  轉換後的數字量顯示在LED數位管上   *
 ************************/


#include <reg52.h>
#include <intrins.h>

typedef unsigned char uchar;
typedef unsigned int uint;

sbit dula = P2 ^ 6;     // 段選信號
sbit wela = P2 ^ 7;     // 位選信號
sbit adWr = P3 ^ 6;     // AD 開始轉換信號,低電平有效
sbit adRd = P3 ^ 7;     // AD 開始讀取信號,低電平有效
sbit adCs = P0 ^ 7;     // AD 片選信號,低電平有效

// LED 數位管段選碼表
uchar code numberTable[] = {
    0x3f, 0x06, 0x5b, 0x4f,
    0x66, 0x6d, 0x7d, 0x07,
    0x7f, 0x6f, 0x77, 0x7c,
    0x39, 0x5e, 0x79, 0x71,
    0x00};

// LED 數位管位選碼表
uchar code welaTable[] = {
    0x5f, 0x6f, 0x77, 0x7b, 0x7d, 0x7e};

void delay5ms();

void showNumOnSelectedLED(uchar number, uchar welaNum);

void main()
{
    uchar i, onesPlace, tensPlace, hundredsPlace, adValue;

    // AD 晶元片選使能
    adCs = 0;

    while (1)
    {
        // 轉換開始
        _nop_();
        adWr = 0;
        _nop_();
        adWr = 1;

        // 顯示數值,放在adWr後,是為了增加AD晶元的轉換時間
        for (i = 0; i < 10; i++)
        {
            showNumOnSelectedLED(onesPlace, 0);
            showNumOnSelectedLED(tensPlace, 1);
            showNumOnSelectedLED(hundredsPlace, 2);
        }

        // adRd讀取轉換後的數字量
        _nop_();
        adRd = 0;
        _nop_();
        adValue = P1;
        adRd = 1;

        // adValue 是讀取到的數字量,然後把個、十、百分離開來
        hundredsPlace = adValue / 100;
        tensPlace = adValue % 100 / 10;
        onesPlace = adValue % 10;
    }
}

/** 
 * @brief  在指定的LED數位上顯示指定的數字
 * @note   例如,number = 3, placeOfNum = 0, 那麼為最右邊的第0個數位管顯示數字3 
 * @param  number: 顯示的數字 0 - F 
 * @param  placeOfNum:  顯示的位置,從右到左,分別是 0 - 6 位
 * @retval None
 */
void showNumOnSelectedLED(uchar number, uchar placeOfNum)
{
    // 送位選數據前關閉所有顯示,防止打開位選鎖存時,
    // 原來段選數據通過位選鎖存器造成混亂
    P0 = 0xff;


    wela = 1;
    P0 = welaTable[placeOfNum];
    wela = 0;
    dula = 1;
    P0 = numberTable[number];
    dula = 0;
    delay5ms();
}

/** 
 * @brief  延時函數
 * @note   
 * @retval None
 */
void delay5ms() //@11.0592MHz
{
    unsigned char i, j;

    i = 9;
    j = 244;
    do
    {
        while (--j)
            ;
    } while (--i);
}

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • ssh遠程登陸到某台機器後,終端經常出現You have new mail in /var/spool/mail/root的提示信息。在不經常查看系統自動生成的郵件或是想查看的時候使用命令查看。停用郵件自動提示:echo "unset MAILCHECK" >> /etc/profile然後sour... ...
  • 最近幾天家裡的筆記本在使用ivacy的時候,老是連接不上,但是用手機登陸同樣帳戶卻可以使用。 排除了帳戶和伺服器端的問題,那應該就出在電腦上了(而且台式機Win7系統沒有問題)。 搜索了一番,終於發現一個有用的方法,將本次解決過程記錄如下。 1,問題現象: VPN連接時,提示“VPN Error: ...
  • uniq命令 作用:輸出或者忽略文件中的重覆行 格式: uniq [option] [file|stdin] 去掉了連續的重覆行.如果只想保留文件中的唯一,可以用選項-u -c:去重覆,並計算每行出現的次數 可以用sort命令排序後,再去重覆,得到的結果 也是唯一的 -d: 只顯示重覆的行 ...
  • 操作容器的命令 鏡像中的容器啟動之後可以在 docker 中操作和查看容器的信息 l docker ps 查看運行的容器,如果想查看全部加上參數-a 即可 l docker create 完整的鏡像名字# 創建容器但是不啟動它 l docker run 完整的鏡像名字# 創建並啟動容器 l dock ...
  • paste命令 作用:合併文件 格式: paste [option] [file] 1,把兩個文件的內容,按行合併 -d 指定分隔符 -s 每個文件占用一行 把一個文件的奇偶行,用=號會換行符號連接 ...
  • 伺服器搭建zabbix運維檢測工具,監控伺服器CPU、記憶體等參數,因為伺服器已存在5.6版本的mysql,版本衝突,不能使用zabbix官方提供的安裝流程。只能選擇源碼安裝。 ...
  • 一,製作U盤啟動盤 隨著個人電腦的“飛入尋常百姓家”,喜歡DIY電腦的發燒友們也越來越多。 安裝系統是DIY最基本的要求,很容易做到; 那麼如果要求用U盤裝系統呢,你可能會說簡單,直接下載個老毛桃或是大白菜一類的軟體一鍵就搞定了; 那麼如果要求用系統自帶的命令行工具製作U盤啟動安裝盤呢? 工具/原料 ...
  • win10更新後,藍牙功能不見了,也沒有打開的選項,設備管理器里也沒有,多了個未知USB設備,重啟無效,重裝藍牙驅動無效,BIOS中的Bluetooth是開的。 試了網上能找到的所有方法,包括更新win10更新、 更新Bluetooth驅動 等都沒有解決 , 解決方案 是: 1、打開設備管理器,卸載 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...