|
本帖最後由 forest162 於 2025-2-21 11:07 PM 編輯
好久不見,真的好一段時間沒來發文了。這是最近完成的開源專案,用台幣7塊錢的新唐N76E003增強型8051製作的時鐘套件,顯示器一樣是用多年前阿乾大那批白光七段顯示器,但是它不單單只是個時鐘套件,在板邊還lay上了所有IO接腳,它還能當作個多用途的開發板!
https://github.com/danchouzhou/003Clock
N76E003是一個增強型MCS-51 MCU,機械週期為1T,即指令週期以1個時鐘週期為單位,且指令完全相容傳統8051。因此相同時脈之下,處理速度會比傳統8051快上許多。18 KB的程式記憶體還能夠劃分為data flash,用來儲存資料或是斷電記憶的功能。此外它還內建了兩組UART、SPI、I2C、ADC、PWM,這些都是相當受歡迎且常用硬體周邊。如果真的要做產品,建議使用今年新出的N76S003,價格還維持在台幣7塊錢,而且還多了SPROM(可以保護關鍵程式碼)的功能。我現在還在用N76E003是因為之前原廠特價囤太多了XD
這個套件本身有時鐘、計時器功能之外,我還將MCU的所有IO接腳設計在電路板上,使它具備良好的擴充能力,如此能夠基於相同的硬體衍伸出更多功能,例如溫濕度計、電壓電流功率計、引擎轉速表等等,這些是我目前想到的功能,也許我會在日後陸續開發出來。
電路圖、電路板也是用免費的開源軟體KiCad來設計。
關於排針的焊點參考了這篇的做法,將焊點交錯開來,這讓我們可以直接插上排針,而不用焊接排針母座,以維持成品的整潔。
https://hackaday.com/2021/08/12/who-needs-pin-headers/
寫8051的程式經常會使用Keil C51、IAR,這些商業軟體免費版本是有code size限制的,例如限制在2KB,那麼N76E003的18 KB就是用不完的;對我們這些玩家付費版本有點吃力。因此我自己用VS Code和SDCC (Small Device C Compiler)建立一個編譯環境,它們都是open-source的工具,無code size限制。只需要將安裝好SDCC和燒錄軟體,在VS Code以資料夾的形式開啟本專案,就可以開始寫程式並增加自己期望的功能。
我將專案取名為003Clock的原因是,它除了能夠使用N76E003之外,還能pin-to-pin相容於Cortex-M23的M2003,以及今年新唐推出的N76S003。同時它們其它的8051系列MCU,MG51、MS51系列也能夠相容。我想當初新唐會將這顆MCU以003命名,也是因為它能夠與STM8S003 pin-to-pin相容,並擁有較優勢的價格。
電路、韌體的原始碼完整放在GitHub上了,有興趣DIY的朋友可以參考看看。
零件不算太難找,新唐的線上商店買到N76E003 / N76S003,保證會是正規貨源。
https://direct.nuvoton.com/tw/n76s003-系列/
https://www.techdesign.com/marke ... c000715/n76s003at20
也可以直接到我蝦皮買整套包好的,電路板、零件真的備很多。
https://shopee.tw/product/174651435/27767006986/
最後附上電路圖、程式碼,有認真看的話大概可以學到開關除彈跳、中斷服務程式、函式指標、SPI介面。
- #include "numicro_8051.h"
- #include "PT6961.h"
- #include "clock.h"
- #define SW1 P17
- STR_TIME_T time;
- STR_TIME_T stopwatch;
- void (*isrFunction)(void);
- void Timer3_ISR(void) __interrupt (16)
- {
- static uint8_t u8counter;
- if ((u8counter & 0x01) == 0)
- {
- clock(&time, 0);
- clock(&stopwatch, 1);
- }
- u8counter ++;
- (*isrFunction)();
- T3CON &= 0xEF; // Clear TF3
- }
- void showTime(void)
- {
- static uint8_t u8counter;
- static int time_int;
- time_int = getTime(&time);
- if ((u8counter & 0x01) == 0)
- {
- pt6961_setNumberFade(time_int, 0);
- }
- else
- {
- pt6961_setNumberFade(time_int, 1);
- }
- u8counter ++;
- }
- void showSecond(void)
- {
- pt6961_setNumberFade(time.second, 1);
- }
- void showStopwatch(void)
- {
- static uint8_t u8counter;
- static int stopwatch_int;
- stopwatch_int = (int)stopwatch.minute * 100 + stopwatch.second;
- if ((u8counter & 0x01) == 0)
- {
- pt6961_setNumberFade(stopwatch_int, 0);
- }
- else
- {
- pt6961_setNumberFade(stopwatch_int, 1);
- }
- u8counter ++;
- }
- void showSetup(uint8_t u8blink)
- {
- static uint16_t u16counter;
- static int time_int, time_int_last;
- time_int = getTime(&time);
- if (u16counter > 1000 || time_int != time_int_last)
- u16counter = 0;
- else
- u16counter ++;
- if (u16counter < 500)
- {
- pt6961_setNumber(time_int, 1);
- }
- else
- {
- switch (u8blink)
- {
- case 1:
- pt6961_writeCommand(0xC0);
- pt6961_writeByte(0x80); // Light up colon only
- break;
-
- case 2:
- pt6961_writeCommand(0xC2);
- pt6961_writeByte(0x80); // Light up colon only
- break;
-
- case 3:
- pt6961_writeCommand(0xC4);
- pt6961_writeByte(0x00);
- break;
-
- case 4:
- pt6961_writeCommand(0xC6);
- pt6961_writeByte(0x00);
- break;
-
- default:
- break;
- }
- }
- time_int_last = time_int;
- }
- void main(void)
- {
- uint16_t u16swCount = 0;
- uint8_t u8mode = 0;
- TA = 0xAA;
- TA = 0x55;
- CKEN |= 0xC0; // EXTEN
- while(!(CKSWT & 0x08)); // ECLKST
- TA = 0xAA;
- TA = 0x55;
- CKSWT |= 0x02; // Switch to external clock source
- while(CKEN & 0x01); // CKSWTF
- TA = 0xAA;
- TA = 0x55;
- CKEN &= 0xDF; // Disable HIRC
- P12_PUSHPULL_MODE;
- P17_QUASI_MODE;
- pt6961_init();
- pt6961_setBrightness(4);
- CKCON |= 0x08; // Timer 0 source from Fsys directly
- TH0 = (uint8_t)(49536 >> 8); // 65536 - 16000
- TL0 = (uint8_t)(49536 & 0xFF);
- TMOD |= 0x01; // Timer 0 mode 1
- TCON |= 0x10; // Timer 0 run
- isrFunction = &showTime;
- RH3 = (uint8_t)(3036 >> 8); // 65536 - 62500
- RL3 = (uint8_t)(3036 & 0xFF);
- T3CON = 0x0F; // Timer 3 run, pre-scalar = 1/128
- EIE1 |= 0x02; // Enable timer 3 interrupt
- EA = 1;
- while(1)
- {
- if (!SW1) {
- u16swCount++;
- if (u16swCount == 2000)
- u8mode++;
- }
- switch (u8mode) {
- case 0:
- isrFunction = &showTime;
- if (SW1) {
- if (u16swCount > 20 && u16swCount < 2000)
- u8mode = 6;
- u16swCount = 0;
- }
- break;
-
- case 1:
- EIE1 &= 0xFD; // Disable timer 3 interrupt
- showSetup(u8mode);
- if (SW1) {
- if (u16swCount > 20 && u16swCount < 2000) {
- if (time.hour < 14)
- time.hour += 10;
- else if (time.hour < 20)
- time.hour = 20;
- else
- time.hour -= 20;
- }
- u16swCount = 0;
- }
- break;
- case 2:
- showSetup(u8mode);
- if (SW1) {
- if (u16swCount > 20 && u16swCount < 2000) {
- if ((time.hour % 10) < 9 && time.hour < 23)
- time.hour += 1;
- else if (time.hour >= 23)
- time.hour -= 3;
- else
- time.hour -= 9;
- }
- u16swCount = 0;
- }
- break;
- case 3:
- showSetup(u8mode);
- if (SW1) {
- if (u16swCount > 20 && u16swCount < 2000) {
- if (time.minute < 50)
- time.minute += 10;
- else
- time.minute -= 50;
- }
- u16swCount = 0;
- }
- break;
- case 4:
- showSetup(u8mode);
- if (SW1) {
- if (u16swCount > 20 && u16swCount < 2000) {
- if ((time.minute % 10) < 9)
- time.minute += 1;
- else
- time.minute -= 9;
- }
- u16swCount = 0;
- }
- break;
- case 5:
- time.second = 0;
- EIE1 |= 0x02; // Enable timer 3 interrupt
- u8mode = 0;
- break;
- case 6:
- isrFunction = &showSecond;
- if (SW1) {
- if (u16swCount > 20 && u16swCount < 2000)
- u8mode = 8;
- u16swCount = 0;
- }
- break;
- /* case 7: u8mode = 0; break; */
- case 8:
- isrFunction = &showStopwatch;
- if (SW1) {
- if (u16swCount > 20 && u16swCount < 2000)
- u8mode = 0;
- u16swCount = 0;
- }
- break;
-
- case 9:
- stopwatch.minute = 0; // Reset stopwatch then return to mode 8
- stopwatch.second = 0;
- u8mode = 8;
- break;
-
- default:
- u8mode = 0;
- }
- P12 = !P12;
- /* 1 ms delay */
- while (!(TCON & 0x20)); // Wait until timer 0 overflow
- TH0 = (uint8_t)(49536 >> 8); // 65536 - 16000
- TL0 = (uint8_t)(49536 & 0xFF);
- TCON &= 0xDF; // Clear TF0
- }
- }
複製代碼
003Clock-firmware.zip
(1.99 MB, 下載次數: 0)
|
評分
-
8
查看全部評分
-
|