痞酷網_PIGOO

 找回密碼
 立即註冊
!!! [系統偵測到廣告阻擋軟體] !!!

如果您覺得痞酷網對您有些許幫助,或者您認同痞酷網的理想,

那麼希望您將痞酷網設定為白名單.

並請在上論壇的時候,動動您的手指,用行動支持我們.

謝謝!
查看: 172|回復: 0

新唐N76E003白光七段顯示器時鐘開發板套件

[複製鏈接]
發表於 昨天 10:58 PM | 顯示全部樓層 |閱讀模式
本帖最後由 forest162 於 2025-2-21 11:07 PM 編輯

好久不見,真的好一段時間沒來發文了。這是最近完成的開源專案,用台幣7塊錢的新唐N76E003增強型8051製作的時鐘套件,顯示器一樣是用多年前阿乾大那批白光七段顯示器,但是它不單單只是個時鐘套件,在板邊還lay上了所有IO接腳,它還能當作個多用途的開發板!
https://github.com/danchouzhou/003Clock
danny-20250119-003Clock-front.JPG

N76E003是一個增強型MCS-51 MCU,機械週期為1T,即指令週期以1個時鐘週期為單位,且指令完全相容傳統8051。因此相同時脈之下,處理速度會比傳統8051快上許多。18 KB的程式記憶體還能夠劃分為data flash,用來儲存資料或是斷電記憶的功能。此外它還內建了兩組UART、SPI、I2C、ADC、PWM,這些都是相當受歡迎且常用硬體周邊。如果真的要做產品,建議使用今年新出的N76S003,價格還維持在台幣7塊錢,而且還多了SPROM(可以保護關鍵程式碼)的功能。我現在還在用N76E003是因為之前原廠特價囤太多了XD

這個套件本身有時鐘、計時器功能之外,我還將MCU的所有IO接腳設計在電路板上,使它具備良好的擴充能力,如此能夠基於相同的硬體衍伸出更多功能,例如溫濕度計、電壓電流功率計、引擎轉速表等等,這些是我目前想到的功能,也許我會在日後陸續開發出來。
danny-20250119-003Clock-back.JPG

電路圖、電路板也是用免費的開源軟體KiCad來設計。
danny-20250221-003clock-pcb-editor.png

關於排針的焊點參考了這篇的做法,將焊點交錯開來,這讓我們可以直接插上排針,而不用焊接排針母座,以維持成品的整潔。
https://hackaday.com/2021/08/12/who-needs-pin-headers/
danny-20250221-003Clock-function.jpg

寫8051的程式經常會使用Keil C51、IAR,這些商業軟體免費版本是有code size限制的,例如限制在2KB,那麼N76E003的18 KB就是用不完的;對我們這些玩家付費版本有點吃力。因此我自己用VS Code和SDCC (Small Device C Compiler)建立一個編譯環境,它們都是open-source的工具,無code size限制。只需要將安裝好SDCC和燒錄軟體,在VS Code以資料夾的形式開啟本專案,就可以開始寫程式並增加自己期望的功能。
danny-20250119-003Clock-vscode-enviroment.JPG

我將專案取名為003Clock的原因是,它除了能夠使用N76E003之外,還能pin-to-pin相容於Cortex-M23的M2003,以及今年新唐推出的N76S003。同時它們其它的8051系列MCU,MG51、MS51系列也能夠相容。我想當初新唐會將這顆MCU以003命名,也是因為它能夠與STM8S003 pin-to-pin相容,並擁有較優勢的價格。
danny-20250119-003-comparison-table.JPG

電路、韌體的原始碼完整放在GitHub上了,有興趣DIY的朋友可以參考看看。
零件不算太難找,新唐的線上商店買到N76E003 / N76S003,保證會是正規貨源。
https://direct.nuvoton.com/tw/n76s003-系列/
https://www.techdesign.com/marke ... c000715/n76s003at20

也可以直接到我蝦皮買整套包好的,電路板、零件真的備很多。
https://shopee.tw/product/174651435/27767006986/
danny-20250119-003Clock-parts.JPG

最後附上電路圖、程式碼,有認真看的話大概可以學到開關除彈跳、中斷服務程式、函式指標、SPI介面。
danny-20241024-003Clock-schematic.png
  1. #include "numicro_8051.h"
  2. #include "PT6961.h"
  3. #include "clock.h"

  4. #define SW1 P17

  5. STR_TIME_T time;
  6. STR_TIME_T stopwatch;
  7. void (*isrFunction)(void);

  8. void Timer3_ISR(void) __interrupt (16)
  9. {
  10.     static uint8_t u8counter;

  11.     if ((u8counter & 0x01) == 0)
  12.     {
  13.         clock(&time, 0);
  14.         clock(&stopwatch, 1);
  15.     }

  16.     u8counter ++;

  17.     (*isrFunction)();

  18.     T3CON &= 0xEF; // Clear TF3
  19. }

  20. void showTime(void)
  21. {
  22.     static uint8_t u8counter;
  23.     static int time_int;

  24.     time_int = getTime(&time);

  25.     if ((u8counter & 0x01) == 0)
  26.     {
  27.         pt6961_setNumberFade(time_int, 0);
  28.     }
  29.     else
  30.     {
  31.         pt6961_setNumberFade(time_int, 1);
  32.     }
  33.     u8counter ++;
  34. }

  35. void showSecond(void)
  36. {
  37.     pt6961_setNumberFade(time.second, 1);
  38. }

  39. void showStopwatch(void)
  40. {
  41.     static uint8_t u8counter;
  42.     static int stopwatch_int;

  43.     stopwatch_int = (int)stopwatch.minute * 100 + stopwatch.second;

  44.     if ((u8counter & 0x01) == 0)
  45.     {
  46.         pt6961_setNumberFade(stopwatch_int, 0);
  47.     }
  48.     else
  49.     {
  50.         pt6961_setNumberFade(stopwatch_int, 1);
  51.     }
  52.     u8counter ++;
  53. }

  54. void showSetup(uint8_t u8blink)
  55. {
  56.     static uint16_t u16counter;
  57.     static int time_int, time_int_last;

  58.     time_int = getTime(&time);

  59.     if (u16counter > 1000 || time_int != time_int_last)
  60.         u16counter = 0;
  61.     else
  62.         u16counter ++;

  63.     if (u16counter < 500)
  64.     {
  65.         pt6961_setNumber(time_int, 1);
  66.     }
  67.     else
  68.     {
  69.         switch (u8blink)
  70.         {
  71.             case 1:
  72.                 pt6961_writeCommand(0xC0);
  73.                 pt6961_writeByte(0x80); // Light up colon only
  74.                 break;
  75.             
  76.             case 2:
  77.                 pt6961_writeCommand(0xC2);
  78.                 pt6961_writeByte(0x80); // Light up colon only
  79.                 break;
  80.             
  81.             case 3:
  82.                 pt6961_writeCommand(0xC4);
  83.                 pt6961_writeByte(0x00);
  84.                 break;
  85.             
  86.             case 4:
  87.                 pt6961_writeCommand(0xC6);
  88.                 pt6961_writeByte(0x00);
  89.                 break;
  90.             
  91.             default:
  92.                 break;
  93.         }
  94.     }

  95.     time_int_last = time_int;
  96. }

  97. void main(void)
  98. {
  99.     uint16_t u16swCount = 0;
  100.     uint8_t u8mode = 0;

  101.     TA = 0xAA;
  102.     TA = 0x55;
  103.     CKEN |= 0xC0; // EXTEN
  104.     while(!(CKSWT & 0x08)); // ECLKST
  105.     TA = 0xAA;
  106.     TA = 0x55;
  107.     CKSWT |= 0x02; // Switch to external clock source
  108.     while(CKEN & 0x01); // CKSWTF
  109.     TA = 0xAA;
  110.     TA = 0x55;
  111.     CKEN &= 0xDF; // Disable HIRC

  112.     P12_PUSHPULL_MODE;
  113.     P17_QUASI_MODE;

  114.     pt6961_init();
  115.     pt6961_setBrightness(4);

  116.     CKCON |= 0x08; // Timer 0 source from Fsys directly
  117.     TH0 = (uint8_t)(49536 >> 8); // 65536 - 16000
  118.     TL0 = (uint8_t)(49536 & 0xFF);
  119.     TMOD |= 0x01; // Timer 0 mode 1
  120.     TCON |= 0x10; // Timer 0 run

  121.     isrFunction = &showTime;

  122.     RH3 = (uint8_t)(3036 >> 8); // 65536 - 62500
  123.     RL3 = (uint8_t)(3036 & 0xFF);
  124.     T3CON = 0x0F; // Timer 3 run, pre-scalar = 1/128
  125.     EIE1 |= 0x02; // Enable timer 3 interrupt
  126.     EA = 1;

  127.     while(1)
  128.     {
  129.         if (!SW1) {
  130.             u16swCount++;
  131.             if (u16swCount == 2000)
  132.                 u8mode++;
  133.         }

  134.         switch (u8mode) {
  135.             case 0:
  136.                 isrFunction = &showTime;
  137.                 if (SW1) {
  138.                     if (u16swCount > 20 && u16swCount < 2000)
  139.                         u8mode = 6;
  140.                     u16swCount = 0;
  141.                 }
  142.                 break;
  143.             
  144.             case 1:
  145.                 EIE1 &= 0xFD; // Disable timer 3 interrupt
  146.                 showSetup(u8mode);
  147.                 if (SW1) {
  148.                     if (u16swCount > 20 && u16swCount < 2000) {
  149.                         if (time.hour < 14)
  150.                             time.hour += 10;
  151.                         else if (time.hour < 20)
  152.                             time.hour = 20;
  153.                         else
  154.                             time.hour -= 20;
  155.                     }
  156.                     u16swCount = 0;
  157.                 }
  158.                 break;

  159.             case 2:
  160.                 showSetup(u8mode);
  161.                 if (SW1) {
  162.                     if (u16swCount > 20 && u16swCount < 2000) {
  163.                         if ((time.hour % 10) < 9 && time.hour < 23)
  164.                             time.hour += 1;
  165.                         else if (time.hour >= 23)
  166.                             time.hour -= 3;
  167.                         else
  168.                             time.hour -= 9;
  169.                     }
  170.                     u16swCount = 0;
  171.                 }
  172.                 break;

  173.             case 3:
  174.                 showSetup(u8mode);
  175.                 if (SW1) {
  176.                     if (u16swCount > 20 && u16swCount < 2000) {
  177.                         if (time.minute < 50)
  178.                             time.minute += 10;
  179.                         else
  180.                             time.minute -= 50;
  181.                     }
  182.                     u16swCount = 0;
  183.                 }
  184.                 break;

  185.             case 4:
  186.                 showSetup(u8mode);
  187.                 if (SW1) {
  188.                     if (u16swCount > 20 && u16swCount < 2000) {
  189.                         if ((time.minute % 10) < 9)
  190.                             time.minute += 1;
  191.                         else
  192.                             time.minute -= 9;
  193.                     }
  194.                     u16swCount = 0;
  195.                 }
  196.                 break;

  197.             case 5:
  198.                 time.second = 0;
  199.                 EIE1 |= 0x02; // Enable timer 3 interrupt
  200.                 u8mode = 0;
  201.                 break;

  202.             case 6:
  203.                 isrFunction = &showSecond;
  204.                 if (SW1) {
  205.                     if (u16swCount > 20 && u16swCount < 2000)
  206.                         u8mode = 8;
  207.                     u16swCount = 0;
  208.                 }
  209.                 break;

  210.             /* case 7: u8mode = 0; break; */

  211.             case 8:
  212.                 isrFunction = &showStopwatch;
  213.                 if (SW1) {
  214.                     if (u16swCount > 20 && u16swCount < 2000)
  215.                         u8mode = 0;
  216.                     u16swCount = 0;
  217.                 }
  218.                 break;
  219.             
  220.             case 9:
  221.                 stopwatch.minute = 0; // Reset stopwatch then return to mode 8
  222.                 stopwatch.second = 0;
  223.                 u8mode = 8;
  224.                 break;
  225.             
  226.             default:
  227.                 u8mode = 0;
  228.         }

  229.         P12 = !P12;

  230.         /* 1 ms delay */
  231.         while (!(TCON & 0x20)); // Wait until timer 0 overflow
  232.         TH0 = (uint8_t)(49536 >> 8); // 65536 - 16000
  233.         TL0 = (uint8_t)(49536 & 0xFF);
  234.         TCON &= 0xDF; // Clear TF0
  235.     }
  236. }
複製代碼

003Clock-firmware.zip (1.99 MB, 下載次數: 0)

評分

8

查看全部評分

您需要登錄後才可以回帖 登錄 | 立即註冊

本版積分規則

關閉

站長小叮嚀上一條 /1 下一條

禁閉室|手機版|連繫我們|痞酷網電子技術論壇

GMT+8, 2025-2-22 04:49 PM , Processed in 0.107155 second(s), 20 queries , Gzip On.

Powered by Discuz! X3.4 Licensed

© 2001-2023 Discuz! Team.