欧美极品高清xxxxhd,国产日产欧美最新,无码AV国产东京热AV无码,国产精品人与动性XXX,国产传媒亚洲综合一区二区,四库影院永久国产精品,毛片免费免费高清视频,福利所导航夜趣136

標題: 用51做了個 PLC:X、Y、高速計數輸入、高速輸出、Modbus等直接用,超低學習成本 [打印本頁]

作者: qsssuv    時間: 2026-3-3 08:41
標題: 用51做了個 PLC:X、Y、高速計數輸入、高速輸出、Modbus等直接用,超低學習成本
本帖最后由 qsssuv 于 2026-3-14 16:40 編輯

大家好,我是一名嵌入式開發者。一直覺得工業 PLC 價格高、定制難,于是決定用 51 單片機從零做一個小型 PLC。現在已經實現了DI、DO、AI、AO、高速計數輸入、Modbus RTU 通信、輔助繼電器、通用數據寄存器、16位通用加計數器、32位通用加減計數器、1ms定時器、10ms定時器、100ms定時器、1s定時器、1min定時器,這個帖子將逐步介紹,項目在proteus上的STC15W4K32S4上實現,若有需要可提供實板原理圖,進行定制專用的MCU-PLC。

2026.3.14
視頻教程已上傳到B站

51hei1.jpg (240.86 KB, 下載次數: 0)

51hei1.jpg

51hei2.jpg (183.39 KB, 下載次數: 0)

51hei2.jpg

作者: qsssuv    時間: 2026-3-3 17:01
本項目是一個已建立好的KEIL工程,下載后直接打開即可。

直接在app_plc文件夾編寫自己的代碼就好了,
圖片中的程序代碼是在Y103輸出500Hz,占空比50%的PWM波形
高速計數輸入計250時,即250/500為0.5s,
在仿真中,將Y103連接到了X0,Y0接了一個LED燈,可以看到LED閃爍。



作者: qsssuv    時間: 2026-3-3 17:33
這里放上proteus的仿真(需要8.15版本)、工程(內含設計說明書)。

PLC單片機proteus仿真(需8.15版本).zip

21.79 KB, 下載次數: 0, 下載積分: 黑幣 -5

v1.0.0.260228.zip

562.76 KB, 下載次數: 0, 下載積分: 黑幣 -5


作者: qsssuv    時間: 2026-3-4 08:14
本帖最后由 qsssuv 于 2026-3-11 08:20 編輯

【通用輸入/通用輸出操作】
X為輸入,Y為輸出。
讀取輸入,直接寫名稱即可。
  1. IF (X0)
  2. {
  3.     ……
  4. }
復制代碼
將輸出置為0的三種寫法:
  1. RST(Y0);
  2. Y0=0;
  3. MOV(0,Y0);
復制代碼
將輸出置為1的三種寫法:
  1. SET(Y0);
  2. Y0=1;
  3. MOV(1,Y0);
復制代碼
將輸入短路至輸出的兩種寫法:
  1. Y0=X0;
  2. MOV(X0,Y0);
復制代碼


作者: hyzqq    時間: 2026-3-4 10:11
感謝樓主,下載學習一下。51做PLC僅供學習原理應該是沒什么問題的
作者: luipingwei    時間: 2026-3-4 13:40
提議降分, 代碼不全, 功能關鍵代碼缺失
作者: qsssuv    時間: 2026-3-5 13:46
本帖最后由 qsssuv 于 2026-3-11 08:20 編輯

【模擬量輸入】
直接讀取值即可:
D0=AI0;
作者: cccc888    時間: 2026-3-5 17:31
plc相關提供一個外部頭文件,而不是在幾個頭文件中
mcu plc。lib中有沒有使用時間限制。
作者: qsssuv    時間: 2026-3-5 20:03
cccc888 發表于 2026-3-5 17:31
plc相關提供一個外部頭文件,而不是在幾個頭文件中
mcu plc。lib中有沒有使用時間限制。

這個LIB沒有使用限制,但是只在仿真中測試通過
作者: qsssuv    時間: 2026-3-6 08:00
【定時器】
所有的定時器,都是倒計時定時器,將從設置的值開始倒計時,若計數值達到0,運行狀態T_STA_RUN,將轉變為計時到達狀態T_STA_OK。
定時器有4種狀態、5種使用方法。
4種狀態分別是:停止(T_STA_STOP)、運行(T_STA_RUN)、暫停(T_STA_PAUSE)、計時到達(T_STA_OK)。
5種使用方法分別是TON、TPAUSE、TRST、TGetSta、TGetVal,用以下例子加以說明。
//若T0定時10ms時間到,則輸出Y0。
IF (TON(T0,10)==T_STA_OK)
{
    SET(Y0);
} ELSE {
    RST(Y0);
}
//時間未到時,若X0輸入,則暫停定時器,若X1輸入,則重置定時器
IF (TGetSta(T0)!=T_STA_OK)
{
    IF (X0) TPAUSE(T0);
    IF (X1) TRST(T0);
}
//將計數值導出到D0
D0 = TGetVal(T0);
注意,定時器定時值的單位為對應時基:如1ms定時器T0,TON(T0,10)表示定時10ms;100ms定時器T100,TON(T100,5)表示定時500ms,以此類推。
作者: qsssuv    時間: 2026-3-6 16:56
【計數器】
計數器有3種狀態,分別是停止(C_STA_STOP)、運行(C_STA_RUN)、計數到達(C_STA_OK)。
16位通用加計數器有2種方法。
第1種方法,加計數:CTU(要使用的計數器,信號源,計數目標值)。
例如使用計數器C0對X0的上升沿,進行加計數,到達10次時,Y0輸出1s后重新開始計數。
  1. IF (CTU(C0,X0,10)==C_STA_OK)  //若計數器C0,捕捉到X0上升沿10次
  2. {
  3.     TON(T50,100);  //啟動1s定時器
  4.     SET(Y0);  //輸出Y0
  5. } ELSE {
  6.     RST(Y0);  //清除Y0
  7. }
  8. IF (TGetSta(T50)==T_STA_OK)  //若1s時間到
  9. {
  10.     RST(Y0);  //清除Y0
  11.     TRST(T50);  //重置定時器
  12.     C16RST(C0);  //重置計數器
  13. }
復制代碼



第2種方法,減計數:CTD(要使用的計數器,信號源,計數目標值)。
例如使用計數器C1對X1的下降沿,進行減計數,到達10次時,Y1輸出2s后重新開始計數。
  1. IF (CTD(C1,NOT(X1),10)==C_STA_OK)  //若計數器C1,捕捉到X0下降沿10次
  2. {
  3.     TON(T50,200);  //啟動2s定時器
  4.     SET(Y1);  //輸出Y1
  5. } ELSE {
  6.     RST(Y1);  //清除Y1
  7. }
  8. IF (TGetSta(T50)==T_STA_OK)  //若計時時間到
  9. {
  10.     RST(Y1);  //清除Y1
  11.     TRST(T50);  //重置定時器
  12.     C16RST(C1);  //重置計數器
  13. }
復制代碼

32位通用計數器有1種方法。CTUD(計數器,加計數信號源,減計數信號源,計數目標值)。
例如使用計數器C200,X0作為加計數信號源,X1作為減計數信號源,當數值到達200時,Y0輸出2s,然后重新計數。
由于32位通用計數器在計數完成后,仍會受到加減操作的影響,導致狀態變更,因此引入輔助繼電器,避免Y0的輸出波動。
  1. IF (M0==0)  //若M0為0
  2. {
  3.     IF (CTUD(C200,X0,X1,200)==C_STA_OK)  //若計數器C200,在X0和X1的計數信號下,達到200次
  4.     {
  5.         TON(T50,200);  //啟動2s定時器
  6.         SET(Y0);  //輸出Y0
  7.         SET(M0);  //置位M0
  8.     } ELSE {
  9.         RST(Y0);  //清除Y0
  10.     }
  11. }
  12. IF (TGetSta(T50)==T_STA_OK)  //若定時時間到
  13. {
  14.     RST(Y0);  //清除Y0
  15.     C32RST(C200);  //重置計數器
  16.     RST(M0);  //清除M0
  17.     TRST(T50);  //重置定時器
  18. }
復制代碼


作者: qsssuv    時間: 2026-3-7 11:00
【高速輸出/PWM】
控制高速輸出有4種方法。分別為以下:
以Y100為例。
輸出控制:PWM_OUT(Y100,頻率,占空比)。頻率范圍為400Hz~100KHz,占空比范圍為0-100,為整數,請勿使用小數。占空比0=無輸出,100=持續高電平。
獲取輸出頻率:PWM_GetFre(Y100)。返回設置的頻率,若未設置,返回0。
獲取輸出占空比:PWM_GetDuty(Y100)。返回設置的占空比,若未設置,返回255。
停止輸出:PWM_STOP(Y100)。Y100將為0。
注:若不進行高速輸出,其默認將為一個通用輸出。
作者: gongzhu    時間: 2026-3-8 10:30
要做PLC起碼也得用STC32吧
作者: qsssuv    時間: 2026-3-8 16:12
gongzhu 發表于 2026-3-8 10:30
要做PLC起碼也得用STC32吧

PCB可以用STC32,但是仿真上沒有,所以用了STC15,其實任何單片機都可以
作者: qsssuv    時間: 2026-3-9 10:31
本帖最后由 qsssuv 于 2026-3-11 08:21 編輯

【高速計數輸入】
需要用到特殊輔助繼電器、特殊數據寄存器,這里使用了一看就明白的變量值。
使能高速計數輸入X0,注意使能后,請勿將其用作通用輸入接口:
  1. DX0_CNT=0;  //設置起始計數值
  2. MX0_OUT=0;  //清除溢出標志
  3. DX0_MAX=100;  //定義設置上限
  4. SET(MX0_EN);  //啟動
復制代碼
停用高速計數輸入X0,停用后,可用作通用輸入接口:
  1. RST(MX0_EN);  //清除使能。除非用戶手動清除計數值DX0_CNT,否則啟動后繼續計數
復制代碼
當起始計數值DX0_CNT達到設置上限DX0_MAX,溢出標志MX0_OUT會置1,并且DX0_CNT從0開始。需要用戶手動清除溢出標志MX0_OUT。
需要注意,受限于MCU的性能,若值范圍為0~255,則計數的設置上限,以及起始計數值,設置時均不可超出此范圍。
若需要使用高速計數輸入X3,將以上代碼中的X0修改為X3使用即可。
作者: qsssuv    時間: 2026-3-10 08:20
【日期和時間】
dhms是一個集合了設備已運行時間的對象。包含天數、時、分、秒。
dhms.day,天,最大到32767。
dhms.hour,時。
dhms.min,分。
dhms.sec,秒。
用戶可將其加載至通用數據寄存器。
作者: qsssuv    時間: 2026-3-11 08:21
【Modbus-RTU從站協議】
通信配置:4800,N,8,1。訪問地址固定為1。
寄存器表就不貼圖了,可以下載下來看設計說明中的詳細內容。
總之,就是直接連上Modscan工具就可以使用,很方便。

在仿真上,你需要安裝虛擬串口驅動,才能使用modscan連接到proteus仿真
在app_plc_reg_update文件中,填寫了默認的更新事件內容,用戶可自定義其它行為
作者: qsssuv    時間: 2026-3-13 11:02
本 log 函數是針對 MCU-PLC 硬件場景定制的日志輸出函數。
/********************************
功能描述:打印到控制臺(串口輸出)
參數說明:*format:格式控制。支持以下格式:
        %d:s16數據
        %u:u16數據
        %ld:s32數據
        %lu:u32數據
        %s:字符串
        %c:ASCII字符
        %X:u16數據的16進制字符串
        %lX:u32數據的16進制字符串
        %[0][1-5]u:以n的寬度顯示u16數據,不足時可前置添0,超過時寬度限制無效
        %[0][1-10]lu:以n的寬度顯示u32數據,不足時可前置添0,超過時寬度限制無效
        %.[0-4]d:對s16數據以小數形式呈現
        %.[0-9]ld:對s32數據以小數形式呈現
        %.[0-4]u:對u16數據以小數形式呈現
        %.[0-9]lu:對u32數據以小數形式呈現
        %.nd:參數1為保留小數位數,參數為2為s16數據
        %.nld:參數1為保留小數位數,參數為2為s32數據
        %.nu:參數1為保留小數位數,參數為2為u16數據
        %.nlu:參數1為保留小數位數,參數為2為u32數據
        %t:參數1為字符串指針。參數2為限制長度,可以是參數1的空間大小-1。將此字符之前的格式化的字符復制到第1個字符串指針位置
        %hs:參數1為u8指針。參數2為限制長度。將此數據轉為十六進制字符串。
        %hn:參數1為u8指針。參數2為限制長度。直接拷貝源數據。
返回值:指向數據緩沖區的指針,除%t參數外,其它功能都會使得該數據區以字符串結束符結束(\0)
********************************/
char *log(char *format, ...);
例如,將AI0打印至窗口
  1. log("AI0:%u\r\n",AI0);
復制代碼

受限MCU的資源,打印多個參數時,可能輸出異常,可以分解進行單個打印。




歡迎光臨 (http://m.raoushi.com/bbs/) Powered by Discuz! X3.1