2026年2月28日 星期六

STM32無中斷排程器以及解釋

coroutine.h

#ifndef __COROUTINE_H__

#define __COROUTINE_H__
#include "pt.h"

#define PT_TIMER_USE_RTC 1

struct timer
{
#if PT_TIMER_USE_RTC
    unsigned int current;
#endif
    unsigned int interval;
    unsigned int last;
};
extern unsigned int timer_expired(struct timer *t);
extern void timer_set(struct timer *t, unsigned int Interval);
extern void set_task(unsigned char id, PT_THREAD((*func)(struct pt *pt)));
extern void add_task(unsigned char id, PT_THREAD((*func)(struct pt *pt)));
extern int check_pt_main(int id);
extern int Idle_enable;
extern struct pt pt_temp[16];
extern void scheduler(void);

#endif


#include "coroutine.h"
#include "main.h"
#include "fifofast.h"

#define SLEEP_DEBUG 0
#define TASK_NUM (16)
PT_THREAD((*task[TASK_NUM])(struct pt *pt));
struct pt pt_main[TASK_NUM];
#define TASK_FIFO_SIZE (32)
_fff_declare(int8_t, tid_fifo, TASK_FIFO_SIZE);
_fff_init(tid_fifo);
#define DIS_INTR() __disable_irq()
#define ENA_INTR() __enable_irq()
int Idle_enable = 0;

void set_task(unsigned char id, PT_THREAD((*func)(struct pt *pt)))
{
    task[id] = func;
}
void add_task(unsigned char id, PT_THREAD((*func)(struct pt *pt)))
{
    if (!pt_main[id].lc)
    {
        _fff_write(tid_fifo, id);
    }
    PT_INIT(&pt_main[id]);
    task[id] = func;
}
int check_pt_main(int id)
{
    return (int)pt_main[id].lc;
}
unsigned int check_cur_task_num(void)
{
    return (_fff_mem_level(tid_fifo));
}
#if PT_TIMER_USE_RTC
#define RTC_SS() (READ_REG(RTC->SSR))
// #define RTC_SS_MAX() ((unsigned int)1024)
#define RTC_SS_MAX() ((unsigned int)1000)
#define RTC_K() ((RTC_SS_MAX() << 8) / 1000)
#define RTC_KS8(n) (((n) * RTC_K()) >> 8)

unsigned int timer_expired(struct timer *t)
{
    // RTC_SS is down count
    unsigned int register pass_count;
    unsigned int register now;

    now = RTC_SS();
    pass_count = (t->last >= now) ? t->last - now : (RTC_SS_MAX() - now) + t->last;
    t->current += pass_count;
    t->last = now;
    return (t->current >= t->interval);
}

void timer_set(struct timer *t, unsigned int interval)
{
    t->interval = RTC_KS8(interval);
    t->last = RTC_SS();
    t->current = 0;
}
#else
unsigned int timer_expired(struct timer *t)
{
    return (unsigned int)(HAL_GetTick() - t->last) >= (unsigned int)t->interval;
}
void timer_set(struct timer *t, unsigned int Interval)
{
    t->interval = Interval;
    t->last = HAL_GetTick();
}
#endif

void scheduler(void)
{
    while (_fff_mem_level(tid_fifo) != 0)
    {
        unsigned char cur_id;
        cur_id = _fff_read(tid_fifo);
        if (PT_SCHEDULE(task[cur_id](&pt_main[cur_id])))
        {
            DIS_INTR();
            _fff_write(tid_fifo, cur_id);
            ENA_INTR();
        }
    }
    Idle_enable = 0;
}

# 協同排程器的運作原理 這個協同排程器(cooperative scheduler)是基於 **Protothreads** 函式庫實作的輕量級多工系統。讓我詳細說明它的運作機制: ## 1. 核心概念:合作式多工 與搶佔式(preemptive)作業系統不同,這個排程器採用**合作式**調度: - 每個任務必須**主動讓出控制權**(透過 `PT_YIELD()` 或 `PT_WAIT_UNTIL()`) - 不會強制中斷正在執行的任務 - 如果某個任務不讓出控制權,其他任務就會被「餓死」 ## 2. 資料結構 ```c PT_THREAD((*task[TASK_NUM])(struct pt *pt)); // 任務函數指標陣列(最多16個) struct pt pt_main[TASK_NUM]; // 每個任務的執行狀態 _fff_declare(int8_t, tid_fifo, TASK_FIFO_SIZE); // FIFO 佇列(最多32個任務ID) ``` - **`task[]`**:儲存每個任務的函數指標 - **`pt_main[]`**:儲存每個任務的 protothread 狀態,其中 `pt.lc`(line continuation)記錄任務上次中斷的位置 - **`tid_fifo`**:就緒佇列,存放準備執行的任務 ID ## 3. 排程器主迴圈 ```c void scheduler(void) { while (_fff_mem_level(tid_fifo) != 0) // 當佇列不為空 { unsigned char cur_id; cur_id = _fff_read(tid_fifo); // 從佇列取出任務ID if (PT_SCHEDULE(task[cur_id](&pt_main[cur_id]))) // 執行任務 { DIS_INTR(); // 關閉中斷 _fff_write(tid_fifo, cur_id); // 將任務ID放回佇列 ENA_INTR(); // 開啟中斷 } } Idle_enable = 0; } ``` **運作流程:** 1. 檢查就緒佇列是否有任務 2. 從佇列頭部取出一個任務 ID 3. 執行該任務的 protothread 函數 4. 如果任務返回非零值(表示還有工作要做)→ 將任務 ID 放回佇列尾部 5. 如果任務返回零(表示任務結束)→ 不放回佇列 6. 重複直到佇列清空 ## 4. Protothreads 的魔法:無堆疊協程 Protothreads 使用一個巧妙的技巧來實現「看起來會阻塞」但實際上不會消耗堆疊的程式碼: ```c PT_THREAD(example_task(struct pt *pt)) { PT_BEGIN(pt); // 執行一些工作 while(1) { PT_WAIT_UNTIL(pt, condition_is_true); // 在此「等待」 // 做某事 PT_YIELD(pt); // 讓出控制權 } PT_END(pt); } ``` **關鍵機制:** - `pt->lc` 儲存一個整數,代表上次讓出控制權的「程式碼位置」 - 每次呼叫任務函數時,會用 `switch-case` 跳到上次的位置繼續執行 - 這樣就能在沒有堆疊的情況下「記住」執行進度 ## 5. 任務管理 **新增任務:** ```c void add_task(unsigned char id, PT_THREAD((*func)(struct pt *pt))) { if (!pt_main[id].lc) // 如果任務尚未初始化 { _fff_write(tid_fifo, id); // 將任務ID加入就緒佇列 } PT_INIT(&pt_main[id]); // 初始化 protothread 狀態 task[id] = func; // 設定任務函數 } ``` **重要特性:** - 任務 ID 是陣列索引,必須保持穩定(0-15) - 如果 `pt_main[id].lc` 非零,表示任務「還活著」 - 任務可以從主程式或中斷服務常式中喚醒 ## 6. 計時器系統 本專案預設使用 **RTC(即時時鐘)** 的子秒暫存器來實現高精度計時: ```c unsigned int timer_expired(struct timer *t) { unsigned int pass_count; unsigned int now = RTC_SS(); // RTC 是遞減計數(999→0) // 計算經過的時間(處理環繞情況) pass_count = (t->last >= now) ? t->last - now : (RTC_SS_MAX() - now) + t->last; t->current += pass_count; t->last = now; return (t->current >= t->interval); } ``` **使用方式:** ```c struct timer my_timer; timer_set(&my_timer, 1000); // 設定 1000ms PT_WAIT_UNTIL(pt, timer_expired(&my_timer)); // 等待計時器到期 ``` ## 7. 關鍵設計要點 **為什麼需要關閉中斷?** ```c DIS_INTR(); _fff_write(tid_fifo, cur_id); ENA_INTR(); ``` 因為中斷服務常式也可能呼叫 `add_task()` 來喚醒任務,如果不保護 FIFO 寫入操作,可能會發生競爭條件導致資料損壞。 **限制:** - 最多 16 個並行任務(`TASK_NUM = 16`) - 就緒佇列最多 32 個條目(`TASK_FIFO_SIZE = 32`) - 如果 32 個插槽全滿,新任務會遺失 **效能考量:** - 任務必須頻繁讓出控制權,否則會增加中斷延遲 - 關鍵區間(critical section)越短越好 - 適合處理 I/O、通訊、LED 動畫等需要「等待」的任務 ## 總結 這個排程器實現了: ✅ 輕量級多工(每個任務只需少量記憶體) ✅ 易於閱讀的「線性」程式碼風格(看起來像會阻塞) ✅ 適合資源受限的 MCU(STM32F072 只有 16KB RAM) ✅ 可從主迴圈或中斷喚醒任務 但需要注意: ⚠️ 任務必須主動讓出控制權 ⚠️ 一個失控的任務會拖累整個系統 ⚠️ 無法利用多核心(單執行緒輪詢)

2024年9月30日 星期一

以平台經濟解析"麥當勞"的營運模式

 用Google找"麥當勞+如何賺錢",可以發現其實本業不是主要賺錢方法。那它不是直接利用本業方式產生收入的方式一般叫業外收入,但這個業外不完全和本業無關,在一定程度上是利用本業產生的品牌效應帶動的,它在經濟學上叫做外部經濟。我先假設這個收入是本店旁同時由總店一起租下的店面,其收入先以"店旁房租"來稱呼。

麥當勞的展店方式就是一種平台,店主感到不好弄的設備,物料,一大堆都已經規劃好了。只差店主實際就任。

再來才是重點,它要如何撃倒"傳統同業"?
  1. 本業營運成本,利用平台上所有店的需求,可以壓下來,總店完全不抽成,所以成本完全反應成產品,產品本身成本是同業最低。
  2. 總店是由"店旁房租"來支撐,完全無需分店額外支付,所以對分店來說,其利潤最大。
只要在其營業地區內只要和對手同價,因為品質及利潤都較高,同業就會慢慢"餓死"。
在極端狀況下,分店就算完全收支平衡,店也不會倒(沒有上繳總店),你想其同業還能活?

這種營收方式有另一個名字="羊毛出在狗身上豬來買單"。
使用者是羊,是省到"漢堡",但會去隔壁的店去消費。
店主是狗,全力顧好本業形象,提升品牌價值,但同時也提升隔壁店的曝光率,間接提升隔壁店房租價。
豬就是隔壁店的店長,為了好的地點,貴也要租下來。

以平台經濟運行下去,公司只會剩二種:提供平台的大企業,利用平台的小公司。
也就是創業看來變簡單,但無法離開平台,也大不起來。
那中型公司?直接被平台提供的企業擠掉,沒有生存空間。
也就是公司大小完全呈現M型化。

2024年9月28日 星期六

資訊時代下"平台經濟"才是行銷重心

 平台化的gogoro會只賣電動機車引擎給其他燃油機車公司,由大家一起推動電動機車。

這樣做就是一種雙贏的起步局。因為其實其他燃油機車並不是不想做電動車,只是起步研發投入過大,但燃油機車要如何cost down確實是是很善長的,長期經營的供應鏈及行鎖鏈皆為完整的。
gogoro也知道最後會走向Tesla一樣以電池使用為主的供應鏈型式,但電動機車的佔有率以及投入資本是這個新型市場的重心。一開始就不要以為自己可以吃下全部,最佳解是將原先的對手全部都拖下水一起做。

以賽局理論來說,若沒有新的環境條件加入,競爭關係是絶對解不開。要合作,作法就是"將餅做大"。也就是gogoro只專心做別人不好做的,那就是電動機車馬達+控制器。然後只賣這套給其他燃油機車公司去做電動車,但價格不可太高,要在對手覺得直接用gogoro的可以省下大量研發費用下,就直接用,只要專心應付市場。以gogoro來說可以免去對手花時間去破解真正的核心技術外,又可以大量生產以降低成本,迅速擴張市場。擴張市場佔有率為電動機車最重要的任務。

第二個最重要的關鍵基礎設施是換電站,這才是最花錢的,其實這個對Tesla也是一樣的。基本上電動機車就是以老二策略仿電動汽車的策略這個方向一定不會錯。這個一樣找燃油機車廠商一起跳下來,因為要賣電動機車一定要做的。就算合資成立另一家只做換電站的公司也是合理的,因為這個市場要能最快成為王者,當然是原先所有的對手全都跳下來做相近產品,但又共用大家不想做的。電動機車馬達以及換電站就是這個市場最燒錢的部分。

平台化,就是做商場生意不管是對手或是供應商就可以進來,每個人都專精做其專攻的部分,大家合作發揮最大效率。但關鍵者,就是商場成立者,能拿得出大家皆贏的大計劃。又不會搞死自己。

在這個資訊化時代,這種行鎖觀念很重要,主因是現代行銷的傳播率太快,已經無法像以前那樣等產品成熟。時間短又要大量投入資本變成一種常態。這對單一公司來說是越來越不可能,要能做到,變成是相近對手都要一起進來,很容易變成要將原先的對手全部聚在一起做事? 要如何才可以做到? 當然是"畫大餅",不是只出張嘴,還要拿得出"雙贏"的方案才是,這種從競爭轉成雙贏的分析方法,就是賽局理論所推展的。

新的大餅可以容納不同的原競爭者外,又要讓自己生存下來,一定要有一個統合核心,自然就會形成一個對外的"平台"。比較像是大型商場或是百貨公司的概念,但主場要如何收入,自然是商場內的"公共財",基於便用者付費原則下,可以實現在最大效率再從中獲利。以電動機車來說,主要就是馬達+換電系統。

平台經濟這個模型,在未來會變成非常普遍,只是這個詞還太新,只好經由這個案例來說明。

2024年9月27日 星期五

含有軟體的產品開發及測試程序

 從個人數位筆記本中移過來,方便查找

  1. 規格及功能規範
    1. 這是由需求及可能要完成的功能列表
    2. 列出檢測規範以免後續設計功能未達成而重來
  2. 軟體,硬體及配件
    1. 成本估算
    2. 時程估算
  3. 各功能操作程序
    1. 這個會影響操作方式
    2. 使用者介面草稿
    3. 核心管理的方式(要採用的軟體主結構)
  4. 功能設定及參數設定
    1. 要參數化部分
    2. 列出軟體模組及項目
  5. 使用者介面
    1. 和客戶確認可能的操作方式
  6. 進階功能編輯及除錯顯示
    1. 規劃如何驗證各功能
    2. 預留功能可以單獨驗證的方法
  7. 自動化程序
    1. 研發驗證用
    2. 找參數用
    3. 留下環境資料供後續分析
  8. 功能及數據驗證
    1. 不同狀況下數據
    2. 和客戶比對功能是否符合
  9. 自動化驗證程序及治具設計
    1. 大量測試
    2. 穩定性及可靠性分析
  10. 產出可信度統計報告
    1. 安規及其他產品測試項目
  11. 試量產
    1. 測有無量產時無法控制因素
    2. 直通率分析
  12. 比對量產差異性(找公差控制條件)
    1. 找量產變異
    2. 確定工廠能力
    3. 量產SOP
  13. 驗收條件及報告
    1. 不同地區需求的安規及檢測項目

2024年5月10日 星期五

引用Lua的一些事

 Lua有分成Load及call二段。Load是將使用者輸入段落轉成binary code。然後用lua_pcall()去執行。

本來是想直接用dll方式引入使用,沒有想到這種型式沒有任何stdio可以用。
用起來可以動作但沒有輸出入,所以判定是沒有用到stdio。只能改用原始碼再引入重編,果然有輸出。
原始的lua.c中有從stdin/stdout做為輸出入。我習慣自己處理輸入而不是用scanf,因為這個函式會卡住其他行程。
故改用loadbuffer()從記憶體做為輸入來源。因為MCU也常常要處理多程序。
再來就是去執行lua_pcall()就會動作。

架好lua核心,當然是要加入使用者要的指令。Lua做得很方便。
使用 luaL_Reg 這個結構矩陣,將指令及函式排起來。最後再用luaLregister()掛進去就可以了。

再來就是寫給Lua調用的C函式。它的外型是固定的,回傳值是放回多少個Lua回傳數目。
以我最常用的招呼函式來寫,會是以下的樣子。




要取用輸入參數,範例如下:
就是取用參數1做為要用的axis,參數2為要啟用的狀態。



要放入回傳值給Lua的範例如下:

可以看到有push三個數值,就是要給lua的值,最後return值就是數目,故這裏給的是3


在某些平台上有時會遇到一個問題,在載入使用者函式庫就當掉,回報原因是釋放了一個空指標。
我又回去看lua.c 發現在載入函式庫時要先停用GC(垃圾收集器),載完後再啟用。


2023年8月19日 星期六

柳比歇夫的時間統計法

 1.只寫做事及花費時間

2.全天記錄

3.統計分析, 分類, 統計正事時間, 統計單項工時, 年度結算
只分工作及休息二類
工作再分: 中心工作, 附加工作, 社會工作
其他的都是休息活動
統計單一工作需要多少工時
找出下腳料

4.決策,制定計劃

簡單才是有效做事的方法,但如何才能找到簡單的方法? 還是要用科學

2023年8月14日 星期一

有關SWV的評估

 有人和Bee說,用SWV可以做很多除錯的事。我去查一下確實很好用,但它需要SWO這支腳。目前手上的ST-Link V2是沒有這支腳。要到ST-Link V3才有。或是上網買ST-Link V2-1這個變型debugger。待弄到手用了再寫後續...

2022年5月4日 星期三

STM32CubeIDE中合併BootLoader

將srecord-1.64-win32中的srec_cat.exe拷貝到專案\Debug之下。

然後將要合併的BootLoader.hex檔也放進來。
寫一個Merge.bat檔,內容為
srec_cat.exe Bootloader.hex -intel ProjectXXX.hex -intel -o ProjectXXX_all.hex -intel
修改Post Build Steps內容



發動Build Project後會自動生成合併檔

2022年4月12日 星期二

STM32 TouchGFX實際應用

 第一個是MCU換了。所以只能回去STM32CubeIDE上做編譯,這個問題不大。

然後再連上一個傳統的TFT,它是240*320 16bit color。
所以運作需要一個graphic buffer,容量為240*320*2 Byte = 153,600 Byte
一個MCU要超過64K RAM都不多。
所以第一個問題是要啟動 PartialFrameBufferManager
問題來了,要除錯看不到。
因為它是用hpp寫出來的,沒有用到就沒有實體程式。
有用到是有實體,但不在cpp檔中就無法設斷點。有時可以設斷點,但停下來很多變數又無法看。
另外若又加入freeRTOS,結果就是不動,還不知卡在那裏。
只好先拿掉freeRTOS,改成單工還可以追,只好先這樣弄。
弄出來的結果是RAM只用20KB,這個可以用的MCU就很多了。MCU不缺ROM,UI多是圖檔及字型檔,但RAM一向很少,RAM放不進去就無法用。

不過就算如此老闆還是想換成本低的MCU,主要是供貨問題。
不過我說沒法,整個專案生成時有150MB,大約一星期就可以生成這樣的量。換另一個MCU要做出類似的程式,沒有產生器,個人覺得進度以月來計。
結論是,TouchGFX確實綁在STM32上,但它可以將原先以月計的UI開發壓縮到以週計。
就看專案型式了,新專案比較適用,因為結案快,一年可以做好幾個案子。
若是cost down別人的,還是算了,光是MCU就壓不下來。

STM32 TouchGFX試用

 有客戶要做案子,希望看到會動的東西。

於是就用STM32的demo板做一個概念性的範例。
使用STM32F476 Discovery板做一個樣子。因為這個板子有支援,完全不需使用STM32CubeIDE及STM32CubeMX就可以更新程式。
然後就會遇到一個C工程師不太想遇到的問題: 升級成C++
個人不太想升,效益不好,90%的工作都在C上,升上去能用幾個案子?
所以只能選擇C/C++混編。
這個算簡單: C程式存成 *.c,不用改。
主要是在cpp內引用.c函式,要在函式前面多加 extern "C"
很快就做出樣本程式,還有Simulator的PC程式可以給客戶看一下。
對方很快的就提出正式規格了。

然後...痛苦的事一個一個來了。

2021年10月28日 星期四

STM32 TouchGFX評估

 因為專案需求UI又很趕的狀況下,只能利用別人的UI工具會比較快。UI後期最麻煩的是當圖型可以顯示,從老闆到業務到客戶每個人都會有意見。修改頻繁但不會是主功能。

個人很早就在想UI其實和MCU要控制的的事其實不太直接相關,其實可以單獨拉出來,用很少的界面函式去控制機器狀態機或是設計就可以了。
在2013年就有公司是利用硬體分開,出的所謂的顯示界面晶片。說穿了也是用另一個MCU將TFT及touch整合。當時採用的界面語言是arduino。不過這個是在不計成本下可行的方案,MCU本身就是有點成本敏感的市場,個人覺得不太可能有什麼量。
回到現在MCU本身的執行能力比以前強大,所以UI又回來了。但市場同時也有變化,手機人手一機。MCU有可能自己管理TFT+touch的UI,也可能利用手機通信產生在手機端的UI。
在架構上就有二個UI會存在,不管是在MCU上管理的UI,或是手機遠端UI。很明顯的核心和UI一定要分開,UI分離下模擬器就更有機會做出來。
個人在開發手機端測試時,MCU上只要有命令解析器就可以了。所以就使用類似終端機的界面就行了。這個很容易驗證,就算不用手機USB就會有這樣的應用。USB上架個VCP(virtual COM port)這個在STM32開發上只要勾個引用,就會帶入,不太需要了解太多就會生成一個USB VCP。USB通信驗證可以用,再轉去手機一般問題不大。
這次剛好遇到需要顯示+touch的案子。除了案子趕,可以預見的是後期只修改UI的非核心工作會很多。不能再用以前的土方法了。重新評估新工具: STM32 TouchGFX

看完資料後,發現TouchGFX可以生成PC模擬器,這個實現了個人很早以前的想法,更確定使用後可以有效降低修改頻率。因為生成的模擬器是沒有實體沒有錯,但所有畫面都可以先在PC上操作,客戶可以先行檢查。另外手機APP公司也可以先利用這個模擬器做手機界面。

再來是工具是如何使用?
大約的流程是這樣(目前還在試用,也許不太正確)。先用CubeMX生成專案,但要引入使用TouchGFX套件。
再來去CubeIDE內可以看到有專案內有多出TouchGFX專案入口檔,點它會開啟TouchGFX designer,它是UI 設計的核心(這個很大,還在研究中)。在designer中可以使用UI物件做編輯,最後再按Gererate Code就會生成程式碼,不過它是生成C++。C++個人一直覺得沒有必要用,因為MCU一般RAM不多,不用到如此複雜的管理。不過在使用TFT的場合下RAM的使用量會增加很多,再加上新式RAM(=OctoSPI SRAM)也出來了,外掛RAM的成本不如以前高。看來C++又要去看一下了。至於PC模擬,它用自帶的GCC編譯器,生成執行檔會在bin/下,要給別人用要整個目錄壓給別人,重點是內有很多DLL檔要一併給。

看得出來touchGFX就是利用MCU HAL函式及PC 的DLL做為其底層。只要函式名相同,就可以在調用HAL或DLL在二個平台上執行。果然只有大公司才有機會做這樣的整合。不過MCU不再是價格之爭,支援工具強大專案產出會有不同的效率。前題是若沒有HAL將MCU底層分開來,這種整合是做不到。
目前評估只到這裏,其他的還在研究中。

2021年8月8日 星期日

行銷5.0心得

 簡單翻過: 沒有說明5個版本行銷分界原因,但有將行為及現象說清楚。


行銷代別:
行銷1.0 產品導向
行销2.0 顧客中心導向
行銷3.0 以人為本行銷
行銷4.0 傳統轉型數位
行銷5.0 科技造福人類

行銷5.0 和 4.0 主要是多了一些行銷工具,一但使用完全壓過4.0。其中大多和AI相關。工具應用的目的再分類,形成新的主體。多的行銷戰術為:
資料行銷
預測行銷
場景行銷
增強行銷
敏捷行銷
以上行銷戰術不是新的,是從遊戲行銷來的。
主因是軟體服務+實體已成新產品。所以實體產品不是客戶唯一選擇。舉例,手機的選用只看硬體規格? 不否認有些X世代的消費者是,但目前人口已經很少了。

所以對遊戲行銷有研究的人來說,只是擴展,並正式納入成為行銷5.0。這也是行銷5.0的目的看起來很模糊(造福人類是什麼行銷?)。

2021年2月20日 星期六

最近用的MCU IDE整理

 STM32CubeIDE, MCU為STM32, UI是Eclipse, 編譯器是GCC

MCUXpresso IDE, MCU為iMX系列, UI是Eclipse, 編譯器是GCC

CodeWarrior IDE, MCU是HCS08, UI是Eclipse, 編譯器是專用及GCC

Simplicity Studio, MCU是C8051F380, UI是Eclipse, 編譯器是Keil C51及GCC

STDV, MCU是STM8, UI是專用, 編譯器是Cosmic

以上的C編譯器都免費使用。

看來會使用Eclipse介面在轉換MCU時就不會不適應。

2020年9月13日 星期日

STM32CubeIDE試用

 改用免費軟體來開發。所以重新試工具。

就簡單編個LED控制程式,程式是沒有問題,因為HAL都限定好名字。

比較有問題的是除錯。

Run為下載後全速跑。好像沒有中間停下來。

Debug是可以單步。也可以看裝置設定。也可以下載記憶體內容。

剩下的就是適應及功能組合。

2020年3月31日 星期二

手遊轉PC趨勢分析

最近微軟大放送無線搖桿,這不算什麼,也許在清庫存。
然後Bee還在玩為數不多的手遊都開始出PC版本,基本上都支援無線搖桿。
這就怪了! 怪事不會連著來,一定有事。
資訊不足,改用反推法。
若手遊要移植到PC,應做那些事?
  1. 使用的電腦語言可以換去PC重編,沒人會想重寫,又會有維護問題,沒有相同的程式碼一定不可能。
  2. 驅動程式要相容,這個不保證,但工一定比第一項來得小
  3. 引擎要相容,主要是3D引擎或是物理引擎。若有同套問題就小。
個人認為2,3項看運氣,但game數量如此多,一定有符合的。
再來就是第1項了。PC軟體主導是微軟,若是微軟的compiler打通這條路,後面會自然生成。
微軟如何造這場局往微軟想要的地方發展?
搖桿是XBOX的! 也就是局勢要往XBox走微軟才有商機。XBox也是一種PC。
這樣路就明顯了,若是手遊轉PC很簡單,同時轉成XBox也會很方便。
重點是PC的操作和XBox有點不同,這個坎要弄平,怎做?
就大量撒搖桿給PC。這下就串起來了。

嗯,這局有很多行銷行為,值得再研究。

2020年3月19日 星期四

手機上C compiler應用心得

算是記錄,因為還沒有找到理想的。
個人目標是做MCU上的程式試跑及除錯用。
(老婆逛街時放置狀態)

Mobile C
簡中介面,範例多。也可以連上手機部分裝置。
但只能單檔,在移轉應用上不方便。
移轉來的程式要另外作業,不容易作這樣的準備。

Cxxdroid
可以使用CMake,但試跑我的直譯器時,出現segment fault,不知道是那裏有問題。VS2019下沒有什麼問題。同程式在Mobile C下沒有問題。

CPP N-IDE
也可以用,相容性不錯。但缺少可以用的make,所以目前也是只能單檔。

2020年2月19日 星期三

工件語言及工作語言的功能及插件功能設計

DXP或是SVG都是工件語言,它只描述工件的樣子,但沒有說是如何做加工。
機器手動作語言是有加工程序,但它有它自己的語言及函式,和工件語言並不相同。
且各家機器人使用的工作語言也都不相同。
所以MCU製作的機器人就有二套語言,一個是工件語言解析器,另一個是它自己動作用的工作語言解析器。
工件語言解析器分解後變成工作語言格式,這是一般工作。
但現在軟體都流行插件,也就是使用者可以加工作程序。很多軟體會後加工DXP檔,就是要加入一些機器才有的工作行為。
若是沒有將工作語言獨立出來,插件功能就無法成形。
所謂的插件,就是工作語言函式,它由使用者從機器操作界面輸入,然後在指定的工件語言指令中插入。
對於使用者來說是工件語言指令插入,實則是分解成工作語言後才插入,只是使用者看不到工作語言層的狀況下會以為是工件指令插入。

本來是想以巨集方式解決,就是使用文章插入的方式做。
但後來想到有可能要解析工件語言參數的狀況,改成用函式插入,這樣就可以在執行時取得參數做判定。

有了工件語言,也有機會做使用者新加指令的可能。
在解析工件語言,若遇到無法解析指令,就轉跳去工作語言的使用者新增指令掛勾,就有機會利用工作語言去做新指令解析並插入對應函式。

在實際上這個插件功能可以做什麼? 主要用在加工中插入檢查功能。
機器手上除了加工手指外,還有camera手指,工件語言不會使用機器檢查機制,就要用插件來做。
變成加工到一半,可以叫camera進來看,簡言之就是拍照存證。
這樣的機器可以由使用者加檢查點,或是改變部分加工行為。

照顧用機器人工作及需求分析

機器人取代人的工作,個人是認為取代照顧工作最多。
此類工作需求量大,照顧對象固定,可以寫成標準照顧程序。
問題出在辨識能力,先不管需求多少計算力,依辨識反應時間可以應用的需求就不同。
一般檢知仍以camera識別為主,其他環境檢知為輔。
辨識反應時間定義為:輸入新的影像資料,辨別出目標物的狀況,並找到對應的處理行為。
依據反應時間不同,應用的目標就不同。
反應時間級的定義:1分鐘級,表示可以在1分鐘到10分鐘內完成。
若是反應等級為10分鐘級的,可以做為植物照顧用,應用於自動化農場。
若是反應等級為1分鐘級的,可以照顧魚類,應用於自動化水產養殖。
若是反應等級為1秒級的,可以照顧動物,應用於自動化畜牧。
反應到0.1秒級的,可以照顧人。
反應到0.01秒的,可以開車。

所以MCU做機器人再和AI聯合,後面還是有很多事可以做。

2020年2月18日 星期二

Sine等面積計算

A=0~90
B=2/90*A
C=arccos(1-B)
D=sin(C)
C,D畫圖
A為角度
B調整分割數目

機器人座標轉換規劃

主要是幾個工作座標轉換之間的關係。
目前機器人都是吃工件檔案,機器手再輸出。中間其實沒有如此簡單。
因為機器人都是由馬達控制,所以馬達要做加減速控制。
馬達吃的指令其實是移動量/單位時間。
將馬達吃的指令也當成是指令,MCU的角色就是直譯器。
主要是將工件指令一路分解到馬達指令。
工件指令可能是DXF檔一類的,實驗或是模擬也可以用SVG來做。
目前有數個轉換在中間。
1.工件指令轉成工件座標:主要是轉成簡單向量,因為向量圖檔有一大堆高階指令,主要是分解成單一向量座標。
2.媒體座標分割:有時輸出座標過大,可能要做分次輸出,或是和檢知器對位做座標修正。
3. 分割/分檔管理:可以做輸出管理,或是重覆次數管理
4.裝置映射:機器人指尖轉換,因為機器人指尖是可以變換的。加工用的和檢查用的不會在同一個座標上。這個就要套上不同的裝置映射。例如鑽頭和camera可以在同手臂上,但看的位置不同,加工中檢查,可以快速轉換。
5.工區座標轉換:因為加工手指可能可以控制,也有被動控制,在這一階完成轉換。平移式手臂比較好轉換,轉軸式手臂就要解反向機器人運動學矩陣。另外機構座標檢查及保護也在這一層。
6.馬達路徑規劃:向量轉成馬達指令,馬達加減速路徑解析,才可以產出移動量/單位時間的指令列表。