2024年10月5日 星期六

老工程師的技術生活(三十五) --- 技術的深度及廣度

過去這一兩年,我一直強調工程師的人生真的不要"窮到只剩下一身功夫"就好。

之所以這麼說:是因為隨著年紀的增長,也真的看得多,體會多。自然感觸就多。

因為都已經這麼一大把年紀了,你說:還有甚麼技術?就算沒摸過,至少從

產品市場上也多多少少也可以知道這些產品背後技術含金量到底有多少?

你說:真的要學,也學不完,往往最後都是卡在一個很現實問題:學了之後,

要如何變現?"上班領薪水?在公司就只做某些產品,你大概在專業分工下,

就只能專注在某項技術領域就好";"創業開公司?那你又不可能甚麼案子都接,

有些東西,你沒摸過,你就自己花資源(時間--工資與金錢--硬體設備)自己慢慢蹲。

蹲了也不一定可以真正的掌握(趕上)客戶或市場"。就算你想靜下心來專攻某個領域,

問題還是一樣:你公司的營運成本哪裡來?若要將技術成果產品變現成為常態收入,

那你也得要多花一點時間在生產銷售財務管理事務性工作上,多一點商業管理活動,

少一點技術研發工作。這些都是非常現實的問題。

所以我們就可以來討論你個人在你的工程師職涯規劃中:到底是技術的深度重要?

還是技術的廣度重要?在工程師的職涯中魚與熊掌可以兼得嗎?

最近跟 @Bee (鄒先生)討論許多從技術角度延伸出的市場經濟議題。的確也讓我們

可以從許多視角來看技術本身的價值。我當然也去了 Bee 的部落格瀏覽一番。

無意間翻出它約近十年前寫的一篇技術文章:

MCU進入C++時代--個人觀點

在該篇文章的時期,我正在募資創業中,那時也真的很少寫程式(不管是軟體或韌體)

而那時創業也只憑著一些既有技術本能與一些在產業中的人脈,去嘗試創造一些

市場機會。當然後來還是有機會又回到技術本行,不斷的撰寫軟體或韌體,

當然自然就又會接觸到該篇文章所提及的議題。

你看:技術這個東西,那就是一種技能而已,只要是在市場應用中用得到,它就是

還活著好好的。隨時可以等你去品嘗的。但有些市場趨勢與先機是講求時效性的。

那我自己就用我自己技術的例子來說明一下:我就是那個還在用組合語言撰寫

韌體程式年代出身的老人家。

上圖是我當初上班公司幫美國LexMark 這家公司的多功能事務機所開發的掃描器

功能模組部分的韌體程式。(已經是二十幾年前了。) 

全部都是組合語言。還是用X8051 組譯器。直接看 C.BAT (批次檔)吧:


	
@Echo off
path=d:\x8051
@echo on
@if not exist 6816_OS.asm goto ERR1
x8051 -q 6816_OS >look
@if errorlevel 1 goto ERR2
link51 -q -c 6816_OS -oOslo3072.usb -x
@if errorlevel 1 goto ERR3

copy *.usb c:\windows\system32\drivers
copy oslofw.usb c:\windows\oslod3071.usb

@goto END
:ERR1
     echo Can't not find input file asm
     pause
     @goto END
:ERR2
     echo ASM compile error ...
     pause
     @goto END
:ERR3
     echo ASM Linker error ...
     pause
     @goto END
:END

@echo off

====

而我們的主程式也很簡單:


	

                include macro.h           ;; The Macro include file
                include ram.h             ;; The Internal Memory include file
                include register.h        ;; The ASIC register include file
                include USBScan.h         ;; The ASIC USB Register include file

MainProgramID   equ     0005

                .chip   8052              ;;  Defined the Core Controller
;;=============================================================================
;; Interrupt Vector Table--- Core Controller
;;=============================================================================
            org     0000h             ;; The Core Controller Start Address 00h
            ljmp    Main              ;;  Code address re-Direction
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++            
            org     0003h             ;; Standard Vector for INT0
XINT0:      ljmp    XINT0P            ;; Code address re-Direction
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
            org     000Bh             ;; Standard Vector for Timer0
TCNT0:      ljmp    TCNT0P            ;; Code address re-Direction
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++            
            org     0013h             ;; Standard Vector for INT1
XINT1:      ljmp    XINT1P            ;; Code address re-Direction
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
            org     001Bh             ;; Standard Vector for Timer1
TCNT1:      ljmp    TCNT1P            ;; Code address re-Direction
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++            
            org     0023h             ;; Standard Vector for USRT
USART:      ljmp    USARTP            ;; Code address re-Direction
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
            org     002Bh             ;; Standard Vector for Timer2
TCNT2:      ljmp    TCNT2P            ;; Code address re-Direction
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=+++++
          
          
          
          
            org     0030h             ;;30H (Reserved for new firmware to Update)
M2ToM1:                               ;; The New Update already in M2 Memory
                                      ;; Enable DMA1 CONTROL REGISTER to Update Firmware
           
            SETP0   DCR               ;;DCR EQU=FF80H=DMA CONTROL REGISTER)
                                      ;; DMA1 perform the M2 to M1
                                        
            nop                       
            nop
            nop
            nop
            nop
            lcall   BootInitial       ;; Re-Boot the New firmware
            reti
            
;==============================================================================
            org     0040h
            ljmp    Idle              ;; The Main Code Start Address
Idle:                                 ;;  The Core Controller Keep IDLE Mode, Waiting for Interrupt Event                                      ;;
            mov     PCON,#00000001b   ;; Keep the Core controller always in IDLE Mode
Main:
            jmp     Idle

===

也就是Include 一大堆副程式或宣告檔案:

一個就是斤斤計較的記憶體定義與分配:\


	
;--------------------------------------------------------------
;             20h~23h使用於USB區域,在這裡並沒有定義
;--------------------------------------------------------------

;---------------------------------------------------------------
;               以下是8052的內部可Bit定址的區域      
;---------------------------------------------------------------

;;------------------------------------------------------ 0x24h
ScanMode_               equ     20h     ;; 1=Color 0=Gray
M2Enough_               equ     21h     ;; 1:M2Full 0:M2Free
Sel_CISorCCD_           equ     22h     ;; Scan Device Select,  1=CIS 0=CCD(no use now)
ExposureTimeSetEn_      equ     23h     ;; set explosure time flag  1:Enable 0:Disable
LampOn?_                equ     24h     ;; Lamp on or not flag?  1:On 0:Off
LampWDT_                equ     25h     ;; Lamp watch dog timer flag 1:On 0:Off
PowerOn?_               equ     26h     ;; Power on or off flag  1:On 0:Off
FewOffsetDMA2_          equ     27h     ;; Few Y-Offset For DMA2 Enable
;;------------------------------------------------------ 0x25h 
YL_Stop_                equ     28h     ;; Last Scan Line Writed
RoutineCallFlag_        equ     29h     ;; Sub-routine Call argument flag!
ColorLineMode_          equ     2Ah     ;; Color Line Mode Set, 1:ColorLineMode, 0:Gray/Pixel
DummyColor_             equ     2Bh     ;; Dummy one Color Line
TGWaitDummyTG_          equ     2Ch     ;; start scan when Buffer Full
DummyFirstLine_         equ     2Dh     ;; Dummy First Line
PreBackTrackOffset_     equ     2Eh     ;; For Motor Back-track offset for Pre-motor Step
TGRepeatTm2Test_        equ     2Fh     ;; Burin Delay Fuction Use,1:Delay is enough  0:Delay excuting!!!
;;------------------------------------------------------ 0x26h
FWDownloadReady_        equ     30h     ;; Firmware self-diagnotics
Tm2FunctionNotReady_    equ     31h     ;; Fw Self-test Timer2 Function
TAOn?_                  equ     32h     ;; TA is turn on or turn off,1:TA turn on 0:TA turn off                              
TAInsert?_              equ     33h     ;; TA is insert or not insert,1:TA insert 0:TA not insert
LampWDTOK_             equ     34h     ;; LampWDT is completed
WeakPower_              equ     35h     ;; When the Flag=1=Scan Length is not enough to Motor Acc, else Flag=0=enough!!
PrinterError_           equ     36h     ;; 
                                        ;; the Motor is ACCing now!!then Motor is ACC Finish the flag will be clear.  
Even_                   equ     37h     ;; The Flag=1=stand for user choise scan solution is 50dpi
;;------------------------------------------------------ 0x27h
;;PowerToggled_           equ     38h     ;; The Flag=1=stand for user choise scan solution is 75dpi
;;UserLampWDTSet_		equ	38h
M2NotEmptyDMA3En_       equ     39h     ;; Check DMA3 startup flag
DMA2WEN_                equ     3Ah     ;; DMA2 Write Enable Flag, 0=Skip 1=No Skip
Scanning_               equ     3Bh     ;; The flag of Scanner is in scanning status
TempPowerLEDOn_         equ     3Ch
PowerStatus_            equ     3Dh
SWRstWDT_               equ     3Eh     ;; Software Reset Watch dog Timer 1:On 0:Off    ;; Allen added--1/19/2001
In16bitMode_            equ     3Fh     ;; Hardware Reset Watch dog Timer 1:On 0:Off    ;; Allen added--1/19/2001
;;------------------------------------------------------ 0x28h
Chamber_     equ     40h
TGDeSpeedCheckHome_     equ     41h     ;;
TGEndScanNextEvent_     equ     42h     ;;  The Next TG Event For EndScan
;;------ Begin  of Definition by Chamber  02/25/2001
Tm2ClockBaseMode_       equ     43h     ;; Mode of Timer2 Clock Base, 0: Fixed, 1: Table
LineModeColorReset_     equ     44h     ;; Color Reset flag for LineMode Scan which hint the Motor Event
MotorTouchDown_         equ     45h     ;; Motor Touchdown for API Command
TGMotorMoveDirection_   equ     46h    ;; Direction of Motor Moving, 1:Back, 0:Fore
TGMotorStepCountDown_   equ     47h    ;; Motor Step CountDown Enable
;;------------------------------------------------------ 0x29h
APICommandReturn_       equ     48h     ;; The Return Argument of The Command Of API, 1:Fail, 0:Success
EndScanSpeedDown_       equ     49h
LineModeRecovery_       equ     4Ah     ;; Motor inter-step Active in scanning flag 1:Enable 0:Disable
;;------ End of Definition By Chamber  02/25/2001
MotorFreeRunAlways_     equ     4Bh     ;; Motor always free-run flag 1:Enable 0:Disable
APICommandBusy_         equ     4Ch
MotorHSTS_              equ     4Dh     ;; Motor Home Start Scan
MotorOn?_               equ     4Eh     ;; 1:MotorOn  0:MotorOff
MotorFreeRun_           equ     4Fh     ;; Motor free run flag 1:Enable 0:Disable
;;------------------------------------------------------ 0x2Ah 
T2Error_                equ     50h     ;; Motor direction, 0:Forward/1:Backward
EndScanMotorBusy_       equ     51h     ;;
MotorStepEn_            equ     52h     ;; 要馬達前進,後退N步時用的Flag
ButtonDeBouncing_       equ     53h     ;; 這是Butuon DeBouncing用的      
KeyPress_               equ     54h     ;; 這是Butuon Fuction雙重檢查用的 
USRMotorSpeed_          equ     55h     ;; Motor Speed Setup By User Flag
MotorMoving_            equ     56H     ;; Motor Moving Under Timer1 ISR 12/03/1999
HWRstWDT_               equ     57h
;;------------------------------------------------------ 0x2Bh
DontGoHomeAfterScan_    equ     58h     ;; 掃瞄後不回Home點旗標 
DontGoHomeBeforeScan_   equ     59h     ;; 掃瞄前不回Home點旗標
MotorStandScan_         equ     5Ah     ;; 原地掃瞄旗標
MotorBackFun_		equ     5Bh     ;; Buffer Full時馬達是否回走旗標 
;;                      equ     5Ch
;;                      equ     5Dh
;;                      equ     5Eh
;;                      equ     5Fh
ExtraFunLSB_B           equ     2Bh             
;;------------------------------------------------------ 0x2Ch  
LEDOffScan_             equ     60h     ;; 關燈掃瞄旗標 
AutoBandWidth_          equ     61h      
PixelMode_              equ     62h     ;; Pixel Mode Scan flag
ShadingBit_             equ     63h     ;; ShadingBit flag
;;                      equ     64h
;;                      equ     65h
;;                      equ     66h
;;                      equ     67h
ExtraFunMSB_B           equ     2Ch
;;------------------------------------------------------ 0x2Dh  
;;----- Begin of Definition by Chamber  02/25/2001 ----
TGSynchronizeFirstLine_   equ     68h     ;; To Synchronize with TG For Start Scan
ScanHomeCheck_            equ     69h     ;; whether Check Home in Start Scan else ?

MotorStepMode_            equ     6Ah     ;; motor Step mode, 0:Full Step, 1:Half Step
TGMotorEventCheck_        equ     6Bh     ;; Scan Ready for Motor Control
ScanModeTGEventMask_      equ     6Ch     ;; Motor Speed variable by Table, 1: Yes, 0:No

Tm2ClockBaseEventMode_    equ     6Dh     ;; Mode of Clock Base for Timer2, 1: Coarse, 0:ClockEvent
TGMotorConstantSpeed_     equ     6EH    ;; Motor is Constant Speed In TG(Fixed Table Offset)
BeginOfTGEveryMotorStage_ equ     6FH    ;; The First TG Event For Per Stage
;;------------------------------------------------------ 0x2Eh
;;--  The Parameters Donot change the order as follow
;;
BackTrackingProcedure        equ     2Eh     ;;;
;;-
UserBackTrackingRequest_     equ     70h     ;; BackTracing Enable or Inhibit ? By User
FWBackTrackingRequest_       equ     71h     ;; BackTracing Enable or Inhibit ? By F/W
TGMotorSpeedDamping_         equ     72h
TGRecoverMotorOffset_        equ     73h     ;; Recovery to StartScan for User Definition
TGBackTrackingWait_          equ     74h     ;; BackTracking Wait M2 Free
TGBackTrackingOffset_        equ     75h     ;; BackTracking According to TG
TGBackTrackingProcess_       equ     76h     ;; Status for Whether BackTracking in Scan or not?
TGStartScanEventSegment_     equ     77h     ;; Motor Home Start Scan
;;------------------------------------------------------ 0x2Fh 
TGMotorFreeRunProcedure      equ     2Fh
;;----
EndOfMotorTableAccess_       equ     78h    ;; The Return value of Table Access Sub-Routine
TGReBuildUpMotorSpeed_       equ     79h    ;; Motor Re-BuildUp Motor Speed in Backtracking
TGMotorFreeRunEvent_         equ     7Ah    ;; Motor Free Run State
;;-
TGDecelerationTransient_     equ     7Bh    ;; Motor Speed Deceleration Transient Stage
TGMotorOffsetSteady_         equ     7CH    ;; Motor Offset in steady speed
TGAccelerationTransient_     equ     7Dh    ;; Motor Speed Acceleration Transient Stage
TGMotorOffsetRemainder_      equ     7Eh    ;; Motor Move Remainder Step By Single TG
TGMotorSpeedTransient_       equ     7Fh    ;; Motor Speed fluctuation stage, other is TGStartScanEvent
;;----- End of Definition by Chamber  02/25/2001 ----
;;------------------------------------------------------

;---------------------------------------------------------------
;             以下是8052的內部可Byte定址的區域      
;---------------------------------------------------------------
YL                      equ     30h     ;;Y方向起掃點
YH                      equ     31h     ;;Y方向起掃點
LengthL                 equ     32h     ;;直接反應要掃多少條Line(例:7020)   
LengthH                 equ     33h     ;;直接反應要掃多少條Line(例:7020)  
XL                      equ     34h     ;;X方向起掃點
XH                      equ     35h     ;;X方向起掃點
WidthL                  equ     36h     ;;直接反應要掃多寬(例:5120) 
WidthH                  equ     37h     ;;直接反應要掃多寬(例:5120) 
;---------------------------------------------------------------
ModeL                   equ     38h     ;;模式設定
ModeH                   equ     39h     ;;模式設定
XDpiL                   equ     3Ah     ;;填到H/W的X方向DPI
XDpiH                   equ     3Bh     ;;填到H/W的X方向DPI
PageSizeL               equ     3Ch     ;;F/W沒有看了
PageSizeH               equ     3Dh     ;;F/W沒有看了
LineContL               equ     3Eh     ;;掃一條Line的資料大小,用於判斷M2是足夠寫入下一條Line
LineContH               equ     3Fh     ;;掃一條Line的資料大小,用於判斷M2是足夠寫入下一條Line
;---------------------------------------------------------------
DpiLRL                  equ     40H     ;;根據不同DPI,實際上Y方向要掃多少條Line(例:300DPI=3510)
DpiLRH                  equ     41H     ;;根據不同DPI,實際上Y方向要掃多少條Line(例:300DPI=3510)
ExtraFunLSB             equ     42H     ;;參數設定   
ExtraFunMSB             equ     43H     ;;參數設定
YDpiL                   equ     44h     ;;Y方向DPI
YDpiH                   equ     45h     ;;Y方向DPI
BackStep                equ     46h     ;;Buffer Full時的後退步數
;;---- Table Offset for F/W Support Resolution ----
DpiTableOffset          equ     47h     ;; Table Offset for F/W Support Resolution in Vertical Direction
;---------------------------------------------------------------
Command                 equ     48h     ;; 存放USB傳下來的Command
ColorSWCnt              equ     49h     ;; Color Switch Counter =1 :Blue, =2:Green, =3:Red
DummyPixel              equ     4Ah     ;; 所要Dummy的點數
LWH                     equ     4Bh     ;; 計數已掃了多少Line,在M2Check中用以和DpiLRH,DpiLRL比較用
LWL                     equ     4Ch     ;; 同上
MotorPhase              equ     4Dh     ;; 存放目前馬達相位
DebugView0              equ     4Eh
DebugView1              equ     4Fh

;---------------------------------------------------------------
YVarH                   equ     50h     ;; 距離Y方向起掃點多遠的值=YH,YL的值
YVarL                   equ     51h     ;; 同上
SWCnt                   equ     52h     ;; Led閃爍頻率計數用
DSLNIN_Cnt              equ     53h     ;; Led閃爍頻率計數用
KeyStatus               equ     54h     ;; 初步存放Button狀態用的 
KeyPressStatus          equ     55h     ;; 準備上傳到軟體的Button狀態用的 
USBEchoKeyStatus        equ     56h     ;; 確定上傳到軟體的Button狀態用的
;----------------------------------------------------------------

;;-----Begin Of Chamber Defined 02/25/2001 -----
TGLineModeM2Event          equ     57h     ;; M2 Check Event for Color Line Mode in Per line
MotorDeSpeedTableOffset    equ     58h     ;; The Offset Of Motor Table in current Scan
TotalStepTransientDeSpeed  equ     59h     ;; The Total Motor Steps in Transient Speed, including Accel. and Decel.
TerminalMotorEventCnt      equ     5Ah     ;; Terminal Motor Event in TG when Scan Activity

TGLineModeM2EventRegister  equ     5Bh     ;; Event Counter Backup & Restore for LineMode in Backtracking Function
TGTm2ClockBaseRegister     equ     5Ch     ;; Event Counter Backup & Restore for LineMode in Backtracking Function
MotorTerminalSpeedOffset   equ     5Dh
Number_LengthOfTable       equ     5Eh     ;; The Number Of Loop Of Length of Motor Table Access
MotorStepTableOffset       equ     5Fh     ;; The Offset of Acceleration Table
;----------------------------------------------------------------
;;----- Timer Event Synchronize with TG ---
;;                     --   Chamber  01/26/2001
;;------**********************************************------
Tm2EventBase            equ     60h     ;;
TGTm2ClockBase          equ     61h     ;; For Motor Next Event Point

TGMotorFixedCnt         equ     62h     ;; The Number of TG of The Steady Motor Speed
TGBufferColorCheckEvent equ     63h     ;; M2 Buffer Check & LineMode Switch Color Event
TGMotorNextEventPt      equ     64h     ;;
TGMotorEventCnt         equ     65h     ;; For TG motor Scaled Event Count
TGMotorEventCntFreeRun  equ     66h     ;; For TG motor Scaled Event Count
YOffsetRemainder        equ     67h     ;;
;---------------------------------------------------------------

;--------------------------------------------------------------
;             68h~77h使用於USB區域在這裡並沒有定義
;--------------------------------------------------------------
;;------**********************************************------
;;;;;       equ     79h     ;; 
;---------------------------------------------------------------
LineM2EventMask         equ     78H     ;;  Line Mode M2 Check Event Mask
;;--
MotorControlTableRegister       equ     79h     ;;The StartAddress of Motor TAble
;; The Order of The Following 24 varibles must be preserved
;;;  CAUTION:
;;      THE Next 17 Memory Buffer is the Registers of Scan Mode Description,
;;      It will be filled with Table after SETWindows Command.
;;      And, the Motor Moving Event will be performed by EveryTG In StartScan.
;;                      --- Chamber 01/26/2001
Tm2EventDescriptionMODE  equ    79h      ;; The Timer2 that synchronize with TG Description
                                         ;; Low Nibble is TimeBase Mode: .0:200us, .1:150us, .2:100us, .3:400us ; Allen 0416
                                         ;; High Nibble is MISC Mode: .4:Reserved, .5:Current, .6:MotorStepMode, .7:AccelectionMode

TGMaxEventCount          equ    7Ah      ;; The Maximun Event In TG for Every TimeBase Mode
;---------------------------------------------------------------
M2BufferCheckEvent       equ    7Bh      ;; M2 Buffer Check Event For Specific TG
BackTrackingM2CheckEvent equ    7Ch      ;; BackTracking M2 Check Event, is The Initial of M2 Check Event, too.
ColorSwitchEventOffset   equ    7Dh      ;; The Offset of M2 Check Event, Special for Color Mode
MotorRecoverDampingTBL   equ    7Eh      ;; Motor Recover Speed Damping Length
MotorEventLength         equ    7Fh      ;; Motor Event Length Description, As Follow
;;------- The Next 12 Variables is Motor Moving Event,
;;         The Address is the registers for TABLE Description from Code Table
;;;---------------------------------------------------------------
;;              Indirect Address
;;;---------------------------------------------------------------
InTGMotorEvent0          equ    80h
InTGMotorEvent1          equ    81h
InTGMotorEvent2          equ    82h
InTGMotorEvent3          equ    83h
;---------------------------------------------------------------
InTGMotorEvent4          equ    84h
InTGMotorEvent5          equ    85h
InTGMotorEvent6          equ    86h
InTGMotorEvent7          equ    87h
InTGMotorEvent8          equ    88h
InTGMotorEvent9          equ    89h
InTGMotorEventA          equ    8Ah
InTGMotorEventB          equ    8Bh
;;--
MotorReserved_A8         equ    8Ah     ;; Reserved
MotorReserved_A9         equ    8Bh     ;; Reserved
MotorReserved_AA         equ    8Ch     ;; Reserved
MotorReserved_AB         equ    8Dh     ;; Reserved
MotorReserved_AC         equ    8Eh     ;; Reserved
MotorReserved_AD         equ    8Fh     ;; Reserved
;;InTGMotorEventB          equ    8Ch
;;InTGMotorEventB          equ    8Dh
;;InTGMotorEventB          equ    8Eh
;;InTGMotorEventB          equ    8Fh
;---------------------------------------------------------------
;---------------------------------------------------------------
;               indirect Address
;---------------------------------------------------------------
LedTurnOnTimeR_RH       equ     90H      ;;以下為曝光時間暫存區 
LedTurnOnTimeR_RL       equ     91H
LedTurnOnTimeR_FH       equ     92H
LedTurnOnTimeR_FL       equ     93H

LedTurnOnTimeG_RH       equ     94H
LedTurnOnTimeG_RL       equ     95H
LedTurnOnTimeG_FH       equ     96H
LedTurnOnTimeG_FL       equ     97H

LedTurnOnTimeB_RH       equ     98H
LedTurnOnTimeB_RL       equ     99H
LedTurnOnTimeB_FH       equ     9AH
LedTurnOnTimeB_FL       equ     9BH

RunningDelayL           equ     9CH
RunningDelayH           equ     9DH
RunningDelayLtemp       equ     9EH
RunningDelayHtemp       equ     9FH

;-------------------------------------USBAPI命令中回覆參數的暫存區
ReturnPrarmeter         equ     A0h
LampWDTTempCountL       equ     A1h     ;;關燈計時器的計數時間
LampWDTTempCountM       equ     A2h     ;;cwh 20001016
LampWDTTempCountH       equ     A3h     ;;同上
HWRstWDTCountL           equ    A4h      ;;HWResetWDT countL
HWRstWDTCountH           equ    A5h      ;;HWResetWDT countH            ;; added end
SWRstWDTCountL           equ    A6h      ;;SWResetWDT countL            ;; Allen added--1/19/2001
SWRstWDTCountH           equ    A7h      ;;SWResetWDT countH
;---------------------------------------------------------------
LampOnTimeCountL         equ    A8h      ;;Lamp的點燈時間
LampOnTimeCountH         equ    A9h      ;;同上
LampWDTCountL            equ    AAh      ;;關燈計時器的計數時間
LampWDTCountM            equ    ABh      ;;同上
LampWDTCountH            equ    ACh      ;;同上
MotorFreeRunCntL         equ    ADh      ;;馬達折返跑的次數
MotorFreeRunCntH         equ    AEh      ;;同上
;---------------------------------------------------------------
PowerDetectCycle	equ	AFh
PowerDetectToggle	equ	B0h
PowerDetectHigh		equ	B1h
;---------------------------------------------------------------
;---------------------------------------------------------------
BurnInWaitTG_MSB        equ     B2h
BurnInWaitTG_LSB        equ     B3h
CalOneMinCntL           equ     B4H
CalOneMinCntH           equ     B5H
MotorWDTCnt		equ	B6H
;;//(M) lufu 0305  ID 80h move b7h
Timer1BaseCnt	EQU	B7H
Timer1Cnt	EQU	B8H

;idVendor_L              equ     B7h     ;; VID  eric wu 0705
;idVendor_H              equ     B8h		;eric wu 0705
idProduct_L             equ     B9h     ;; PID
idProduct_H             equ     BAh
bmParam_L               equ     BBh                                
bmParam_H               equ     BCh  
iProduct                equ     BDh     ;; 0:USB Device, 2=USB Scanner
bmAttributes            equ     BEh     ;; b7=1, b6=1:self power, b5=1:remote wakeup, b4..0=0



;;//(M) lufu end
;---------------------------------------------------------------
;            C0h~FFh  Reserved for Firmware Code Stack !!!
;---------------------------------------------------------------

P0              equ     80h
P0.0            equ     80h
P0.1            equ     81h
P0.2            equ     82h
P0.3            equ     83h
P0.4            equ     84h
P0.5            equ     85h
P0.6            equ     86h
P0.7            equ     87h

P1              equ     90h
P1.0            equ     90h
P1.1            equ     91h
P1.2            equ     92h
P1.3            equ     93h
P1.4            equ     94h
P1.5            equ     95h
P1.6            equ     96h
P1.7            equ     97h

P2              equ     A0h
P2.0            equ     A0h
P2.1            equ     A1h
P2.2            equ     A2h
P2.3            equ     A3h
P2.4            equ     A4h
P2.5            equ     A5h
P2.6            equ     A6h
P2.7            equ     A7h

P3              equ     B0h
P3.0            equ     B0h
P3.1            equ     B1h
P3.2            equ     B2h
P3.3            equ     B3h
P3.4            equ     B4h
P3.5            equ     B5h
P3.6            equ     B6h
P3.7            equ     B7h

===

大家也可以從這程式中的註解可以看到:那時我才入行兩三年而已。我還是非科班

出身韌體工程師,但我已經負責整個韌體開發(包含USB 介面),所以我才以過來人

的經驗告訴大家:

學技術最快的捷徑,就是去找個負得起你薪水的公司,找個專案產品計畫作技術吧

這個專案還是肩負著公司創業成敗的關鍵之一啊。幫人家美國公司的產品設計案。

另外除了副程式之外,為了讓組合語言維護容易就是會定義一大堆 Macro:

	
;==============================================================================
EPPWriteM2     .macro
                mov     A,#11101100b    ;;b4=0:M2 b3=1:Write b2=1:EPP
                mov     DPTR,#D3CR
                movx    @DPTR,A
               .endm
;==============================================================================
EPPReadM2      .macro
                mov     A,#11100100b    ;;b4=0:M2 b3=0:Read b2=1:EPP
                mov     DPTR,#D3CR
                movx    @DPTR,A
               .endm
;==============================================================================
EPPDMA3Enable  .macro
                SETP1   D3CR                ;DMA3 Load Byte Counter
                SETP0   D3CR                ;DMA3 Enable
               .endm
;==============================================================================
EPPDMA3Disable .macro
                CLRP0   D3CR                ;DMA3 Disable
               .endm
;==============================================================================
;;註:把#IDX值搬到DPTR,然後IDATA的值搬到ACC,再把ACC的值搬到DPTR所指的位址中
REG_WR         .macro   idx, idata
                mov     DPTR, #idx
                mov     ACC, idata
                movx    @DPTR, ACC
               .endm
;==============================================================================
;;註:把#IDX值搬到DPTR,然後DPTR的內含再搬到ACC中
REG_RD         .macro   idx
                mov     DPTR, #idx
                movx    ACC, @DPTR
               .endm
;==============================================================================
GETREG         .macro   addr1, addr2
                mov     DPTR,#addr1
                movx    A,@DPTR
                mov     addr2,A
               .endm
;==============================================================================
;;將會代入一個值
;;代入DPTR=idx 
;;把ACC這個值寫入外部  RAM DPTR所指的位址上(ACC的值就決定了idx的值
;;END MARCO 回去原程式
ACC2IO         .macro   idx
                mov     DPTR, #idx
                movx    @DPTR, ACC
                endm
;------------------------------------------------------------------------------
SETPORT        .macro   addr, data
                mov     DPTR,#addr
                mov     A,#data
                movx    @DPTR,A
               .endm
;==============================================================================
SETP0          .macro   addr
                mov     DPTR,#addr
                movx    A,@DPTR
                setb    A.0
                movx    @DPTR,A
               .endm
;==============================================================================
SETP1          .macro   addr
                mov     DPTR,#addr
                movx    A,@DPTR
                setb    A.1
                movx    @DPTR,A
               .endm
;==============================================================================
SETP2          .macro   addr
                mov     DPTR,#addr
                movx    A,@DPTR
                setb    A.2
                movx    @DPTR,A
               .endm
;==============================================================================
SETP3          .macro   addr
                mov     DPTR,#addr
                movx    A,@DPTR
                setb    A.3
                movx    @DPTR,A
               .endm
;==============================================================================
SETP4          .macro   addr
                mov     DPTR,#addr
                movx    A,@DPTR
                setb    A.4
                movx    @DPTR,A
               .endm
;==============================================================================
SETP5          .macro   addr
                mov     DPTR,#addr
                movx    A,@DPTR
                setb    A.5
                movx    @DPTR,A
               .endm
;==============================================================================
SETP6          .macro   addr
                mov     DPTR,#addr
                movx    A,@DPTR
                setb    A.6
                movx    @DPTR,A
               .endm
;==============================================================================
SETP7          .macro   addr
                mov     DPTR,#addr
                movx    A,@DPTR
                setb    A.7
                movx    @DPTR,A
               .endm
;==============================================================================
CLRP0          .macro   addr
                mov     DPTR,#addr
                movx    A,@DPTR
                clr     A.0
                movx    @DPTR,A
               .endm
;==============================================================================
CLRP1          .macro   addr
                mov     DPTR,#addr
                movx    A,@DPTR
                clr     A.1
                movx    @DPTR,A
               .endm
;==============================================================================
CLRP2          .macro   addr
                mov     DPTR,#addr
                movx    A,@DPTR
                clr     A.2
                movx    @DPTR,A
               .endm
;==============================================================================
CLRP3          .macro   addr
                mov     DPTR,#addr
                movx    A,@DPTR
                clr     A.3
                movx    @DPTR,A
               .endm
;==============================================================================
CLRP4          .macro   addr
                mov     DPTR,#addr
                movx    A,@DPTR
                clr     A.4
                movx    @DPTR,A
               .endm
;==============================================================================
CLRP5          .macro   addr
                mov     DPTR,#addr
                movx    A,@DPTR
                clr     A.5
                movx    @DPTR,A
               .endm
;==============================================================================
CLRP6          .macro   addr
                mov     DPTR,#addr
                movx    A,@DPTR
                clr     A.6
                movx    @DPTR,A
               .endm
;==============================================================================
CLRP7          .macro   addr
                mov     DPTR,#addr
                movx    A,@DPTR
                clr     A.7
                movx    @DPTR,A
               .endm
;==============================================================================
;;註:下面程式是要把代入的數值指向DPTR,再把DPTR所指的外部內含值搬到ACC中
GETPORT        .macro   addr
                mov     DPTR,#addr
                movx    A,@DPTR
               .endm
;=============================================================================
;把DMA CONTROL REGISTER的BIT7設1,即LAST SCAN FLAG=1
LastScan       .macro
                SETP7   DCR
               .endm
;==============================================================================
;;把DMA CONTROL REGISTER的BIT=1,即DMA3已經準被好啟動了!
UsrDf1ImageReq .macro
                SETP2   DCR
               .endm
;==============================================================================
;;把DMA CONTROL REGISTER的BIT=1,即DMA2已經準被好啟動了! 
DMA2Enable     .macro
                SETP1   DCR
               .endm
;==============================================================================
;;把DMA CONTROL REGISTER的BIT=1,即DMA1已經準被好啟動了! 
DMA1Enable     .macro
                SETP0   DCR
               .endm
;==============================================================================
;;把DMA CONTROL REGISTER的BIT=0,即將DMA3關閉
UsrDf1PCReq    .macro
                CLRP2   DCR
               .endm
;==============================================================================
;;把DMA CONTROL REGISTER的BIT=0,即將DMA2關閉
DMA2Disable    .macro
                CLRP1   DCR
               .endm
;==============================================================================
;;把DMA CONTROL REGISTER的BIT=0,即將DMA1關閉
DMA1Disable    .macro
                CLRP0   DCR
               .endm
;==============================================================================
;;把DMA CONTROL REGISTER BIT7 CLEAR掉
NotLastScan    .macro
                CLRP7   DCR
               .endm
;==============================================================================
;;把DMA CONTROL REGISTER BIT6=1,即不允許DMA2 WRITE TO M2
DMA2Skip       .macro
                SETP6   DCR                 ; DMA2 Skip Line, Interrupt No Write
               .endm
;==============================================================================
;;把DMA CONTROL REGISTER BIT6=0,即允許DMA2 WRITE TO M2
DMA2No_Skip    .macro
                CLRP6   DCR
               .endm
;=============================================================================
EppDataFW      .macro                      ;; EPP Data reverse, PC<--fw .endm="" .macro="" data="" data_oe="1" epp="" eppdatabw="" pc--="" ppdsr="" reverse="" setp7="">FW
                CLRP7   PPDSR               ;; DATA_OE = 0, Default
               .endm
;============================================================================== 
UsrDf1BySW     .macro
                SETP6   PPDSR
               .endm
;==============================================================================
UsrDf1ByHW     .macro
                CLRP6   PPDSR
               .endm
;==============================================================================
SetWait        .macro
                SETP1   PPDSR
               .endm
;==============================================================================
SetUsrDf1      .macro
                SETP2   PPDSR
               .endm
;==============================================================================
SetUsrDf2      .macro
                SETP4   PPDSR
               .endm
;==============================================================================
SetUsrDf3      .macro
                SETP3   PPDSR
               .endm
;==============================================================================
ClrWait        .macro
                CLRP1   PPDSR
               .endm
;==============================================================================
ClrUsrDf1      .macro
                CLRP2   PPDSR
               .endm
;==============================================================================
ClrUsrDf2      .macro
                CLRP4   PPDSR
               .endm
;==============================================================================
ClrUsrDf3      .macro
                CLRP3   PPDSR
               .endm
;==============================================================================
;註:清除OVER RUN 的FLAG
CLROverRunFlag .macro
                mov     A,#11111101b
                mov     DPTR,#TopIntSt
                movx    @DPTR,A
               .endm
;==============================================================================
;;註:清除DMA2的FLAG
CLRDMA2Flag    .macro
                mov     A,#11111011b
                mov     DPTR,#TopIntSt
                movx    @DPTR,A
               .endm
;==============================================================================
;;註:清除DMA3的FLAG
CLRDMA3Flag    .macro
                mov     A,#11110111b
                mov     DPTR,#TopIntSt
                movx    @DPTR,A
               .endm
;==============================================================================
CLRE4WFlag     .macro
                mov     A,#11101111b
                mov     DPTR,#TopIntSt
                movx    @DPTR,A
               .endm
;==============================================================================
CLRE4RFlag     .macro
                mov     A,#11011111b
                mov     DPTR,#TopIntSt
                movx    @DPTR,A
               .endm
;==============================================================================
CLRECPFlag     .macro                              ;;  ECP Write (03/06/99)
                mov     A,#10111111b
                mov     DPTR,#TopIntSt
                movx    @DPTR,A
               .endm
;=============================================================================


;;註:填入任何值到REGISTER中,便會產生  RESET WATCH DOG的作用
ClrWDT         .macro
                SETPORT WDTRR, 068h
                SETPORT WDTRR, 001h
               .endm
;==============================================================================
IO_Space       .macro
                db      75h,91h,01h
               .endm
;==============================================================================
Mem_Space      .macro
                db      75h,91h,00h
               .endm

;==============================================================================
AFEPowerOn     .macro
;;B7:Wakeup,   b6:Reversed,    b5:BIAS,        b4:CDS2
;;B3:CDS1      b2:CDS0         b1:PGA          b0:ADC

                REG_WR  ASR, #00000000b         ;; AFE Power On
;;----------------------------------
;;              REG_RD  ASR
;;              anl     A, #11000000b           ;; Keep b7,b6 status
;;              movx    @DPTR, A
;       .if Plustek=1
;;//(+) LUFU 0118 ADD FOR EMI
;                SETP6  H1RR                    ;;b7:Polarity b6:enable b5-0:Rise value
;                SETP6  H2RR                    ;;b7:Polarity b6:enable b5-0:Rise value
;               SETP6   RS1RR                   ;;b7:Polarity b6:enable b5-0:Rise value
;                SETP6  SHRRR                   ;;b7:Polarity b6:enable b5-0:Rise value
;;//(+) LUFU 0118 END
;       .endif
               .endm
;==============================================================================
AFEPowerOff    .macro
;;b7:Wakeup,   b6:Reversed,    b5:BIAS,        b4:CDS2
;;b3:CDS1      b2:CDS0         b1:PGA          b0:ADC
 
                REG_WR  ASR, #00111111b         ;; AFE Power Off
;;----------------------------------
;;              REG_RD  ASR
;;              orl     A, #00111111b           ;; Keep b7,b6 status
;;              movx    @DPTR, A
;       .if Plustek=1
;;//(+) LUFU 0118 ADD FOR EMI
;                CLRP6  H1RR                    ;;b7:Polarity b6:enable b5-0:Rise value
;                CLRP6  H2RR                    ;;b7:Polarity b6:enable b5-0:Rise value
;               CLRP6   RS1RR                   ;;b7:Polarity b6:enable b5-0:Rise value
;                CLRP6  SHRRR                   ;;b7:Polarity b6:enable b5-0:Rise value
;;//(+) LUFU 0118 END
;       .endif
               .endm
;==============================================================================
;;ClrDMA2L2Buf .macro
;;              REG_RD  DMACR           ;; Clear DMA2 Level 2 Buffer
;;              setb    A.1
;;              movx    @DPTR, A
;;              clr     A.1
;;              movx    @DPTR, A
;;             .endm
;==============================================================================
SelExSRAM      .macro
;;              REG_RD  DMACR           ;; Clear DMA2 Level 2 Buffer
;;              setb    A.0
;;              movx    @DPTR, A
               .endm
;==============================================================================
SelInSRAM      .macro
;;              REG_RD  DMACR           ;; Clear DMA2 Level 2 Buffer
;;              clr     A.0
;;              movx    @DPTR, A
               .endm
;;=============================================================================
CATCSave       .macro
;;              REG_RD  GPIODR          ;; For 6801071 Phase_A/B
;;              anl     A, #11011111B
;;              movx    @DPTR, A
;;              orl     A, #00100000B
;;              movx    @DPTR, A
               .endm

;==============================================================================
SelectCIS_Mode .macro
                REG_RD  TGCR
                setb    A.1
                movx    @DPTR, A
               .endm
;;=============================================================================
SelectCCD_Mode .macro
                REG_RD  TGCR
                clr     A.1
                movx    @DPTR, A
               .endm    
;;=============================================================================
DisableTimingGenerater .macro
                REG_RD  TGCR
                clr     A.0
                movx    @DPTR, A
               .endm    
;;=============================================================================
EnableTimingGenerater .macro
                REG_RD  TGCR
                setb    A.0
                movx    @DPTR, A
               .endm    
;;=============================================================================                         

SelectBlueAFEChannel  .macro
                clr     A
                ACC2IO  OFFM0RR
                ACC2IO  PGAM0RR
                ACC2IO  GAINM0RR
                ACC2IO  OFFM1RR
                ACC2IO  PGAM1RR
                ACC2IO  GAINM1RR
               .endm
;==============================================================================
SelectRedAFEChannel  .macro
                mov     A, #80H
                ACC2IO  OFFM0RR
                ACC2IO  PGAM0RR
                ACC2IO  GAINM0RR
                clr     A
                ACC2IO  OFFM1RR
                ACC2IO  PGAM1RR
                ACC2IO  GAINM1RR
               .endm
;==============================================================================
SelectGreenAFEChannel  .macro
                clr     A
                ACC2IO  OFFM0RR
                ACC2IO  PGAM0RR
                ACC2IO  GAINM0RR
                mov     A, #80H
                ACC2IO  OFFM1RR
                ACC2IO  PGAM1RR
                ACC2IO  GAINM1RR
               .endm
;==============================================================================
SetTGtoPD      .macro
;;              REG_WR  PPHDR, #00000111b       ;; For  LED & CIS LED
;;              REG_WR  PPDSR, #80h             ;; b7=1 for PD0~7 Output Enable
;;              REG_RD  SCR
;;              orl     A, #10000000b
;;              movx    @DPTR, A
;;              
;;              REG_RD  TGCR
;;              setb    A.3
;;              movx    @DPTR, A
               .endm

;==============================================================================
Timer1Disable   .macro
                clr    TR1
                clr    ET1
                .endm

;==============================================================================
;; b5=1:Suspend external X1 mode, output to GPIO7
SetGPIO7toSuspend   .macro
                mov     A, TSTRtemp
                setb	A.5
                ACC2IO  TSTR
                mov     TSTRtemp, A    
 
                .endm
                
;==============================================================================
;; b5=0:disable Suspend external X1 mode, output to GPIO7
SetGPIO7toIO:   .macro
                mov     A, TSTRtemp
                clr     A.5
                ACC2IO  TSTR
                mov     TSTRtemp, A    
                .endm
                
;==============================================================================
;; b6=1 will set SDA->GPIO0, SCL->GPIO1
SetSDA2IO:      .macro
                mov     A, TSTRtemp
                setb    A.6
                ACC2IO  TSTR
                mov     TSTRtemp, A
                .endm
                
;==============================================================================

---

我要告訴年輕人說:這些東西不要再學了,這是我們那個年代的宿命。你還想:

用C++ 寫韌體?都還沒看到 C 語言呢。

之所以這麼歹命?就因為公司為了賺錢,就得斤斤計較硬體成本。況且那時候

也沒當下這麼先進的半導體製程與高效能的MCU IP 可以用啊。

那個時代不要說:要談技術的廣度啦,就連要談技術的深度也非常有限啊。

但現實的是:這個案子是我最後一個用組合語言做產品,當然也因為執行績效

很好,我就升官到大公司去當部門主管,也開始用 C 語言開發 8051  SOC 產品了。

當然就可以進一步靈活應用 C 語言的優勢了,但這也是因為在硬體支援上有比較

寬裕的記憶體容量,這是我們公司自行設計的 SOC 產品。


	
/*++

Copyright (c) 2001 XXXXX Technology Co., Ltd.

Module Name:

        main.c

Abstract:

        Module related to main routine

Environment:

        Keil C51 Compiler

Revision History:

        08/28/2001      Chi-Yeh Tsai    created

--*/

//=============================================================================
//Header file
//=============================================================================
#include "general.h"
#include "main.h"
#include "initio.h"
#include "setmode.h"
#include "storage.h"
#include "timer.h"
#include "bulkout.h"
#include "cardlink.h"
#include "ctlsetup.h"
#include "uiflow.h"
#include "L2_ADSP.h"
#include "DSPui.h"
#include "usbmsdc2.h"
#include "SCSI.h"
#if (MLUN_OPTION)
#include "usbMLUN.h"
#endif
#include "SPL10.h"
#include "LCD1.h"
#include "doslink.h"
#include "dosvar.h"
#include "dosusr.h"
#include "doserr.h"
#include "audiocodec.h"

#include "smcfunc.h"
#include "smcvar.h"

//
extern union USB_VendorDeviceStringUnion
{	
	UCHAR	USB_VendorConfigurationString[144];
	USB_VendorDevice	SCSI_Vendor;
} USB_VendorDeviceString;

//=============================================================================
//Symbol
//=============================================================================
// WMP3
#if (SIMULATE == 1)
sbit   DbgP11   ;          /* Verify I/O Port 1 : */
sbit   DbgP12   ;          /* Verify I/O Port 2 : */
sbit   DbgP14   ;          /* Verify I/O Port 4 : */
sbit   DbgP15   ;          /* Verify I/O Port 5 : */
sbit   DbgP16   ;          /* Verify I/O Port 6 : */
sbit   DbgP17   ;          /* Verify I/O Port 7 : */


//-------------------------------------
UCHAR   bdata   MainLoop_Event = 0x00;
//-------------------------------------
sbit    _UIEvent        = 0;


#else

//-------------------------------------
UCHAR   bdata   MainLoop_Event = 0x00;
//-------------------------------------
sbit    _UIEvent        = MainLoop_Event^0;


#endif

//=============================================================================
//Variable
//=============================================================================
bit     _G_DispUSBBSY;
bit     _G_Storage_Full;
bit     _G_USB_or_Batt_Power;
bit     _G_LowBatt_State;
bit     _G_Battery_ChargeFull;
bit     _G_USB_Setup_Ack;       //plug out USB clear it
bit     _G_USB_Setup_Interrupt1;      //UI remove MSDC clear it
bit     _G_USB_PowerPlug_Interrupt;
bit	_G_USB_LockTG0, _G_USB_LockTG1;
//----
//----------- @patch@061603@chamber@User Define Vendor_PID/VID!
//----
bit    	_G_GetRevBlockPVID;

bit     _G_Disp_PC;
data	BIT	_MP3Only, _OldDSP;
//bit flag
//data    BIT     G_btSoftwareResetFlag = 0;
data    BIT     G_btStopStream = 0;
data    BIT     G_btEP0Intr;
data    BIT     G_btBulkIntr;
data  	BIT  	_G_USBConnect;
data    BIT     _G_ucSuspend;
//data    BIT     _G_USBSuspendPermit;
data    BIT  	_GPlayPause;
data    BIT	_G_KeyScanTg;
data 	BIT	_G_Storage_Error;
data	BIT	_G_FAT32Error;
data    UCHAR   MCUSTDAdress;
data    UCHAR	G_DSPPrimeMODE;
data    UCHAR   G_DSPMinorMODE;
//
//----------------------------------
//lock fields of USB device request
//----------------------------------
//patch4.5@richie@mlun begin
extern	xdata UCHAR G_ucMSDC_MLUN;
//patch4.5@richie@mlun end
//patch4.5@richie@vender info begin
xdata UCHAR	G_ucMSDC_CARD;
xdata UCHAR	G_ucMSDC_BUILT_IN;
//patch4.5@richie@vender info end
#if (USBVendor_OPTION==1)
//state	and	error code
xdata	UCHAR	G_ucState;
xdata	UCHAR	G_ucState2;	//cch@10/15
#endif

data    UCHAR   G_bRequestLock = 0;
//data    UCHAR   G_bRequestLog = 0;
//data    USHORT  G_wIndexLock = 0;
//data    USHORT  G_wValueLock = 0;

xdata   UCHAR   G_UI_USBConnect;
xdata   UCHAR 	G_PLAY_DPC;
xdata   UCHAR   G_Play_EQ;
xdata   UCHAR 	G_STATE;
xdata   UCHAR   G_EVENT;
xdata   UCHAR 	G_DISPLAY_Min;
xdata   UCHAR   G_DISPLAY_Sec;
xdata   UCHAR   G_Time_SecBase;
xdata   UCHAR 	G_UIMODE;
xdata   UCHAR 	G_DSP_Volume;
xdata   UCHAR	G_PLAY_SeqMode;
xdata   UCHAR   G_LCDPanel_GroupNum;
xdata   UCHAR   G_Battery_GroupNum;
xdata   UCHAR   G_LowBatt_SecondCount;
xdata   UCHAR   G_Battery_Level;
xdata   UCHAR   G_AB_Cnt;
xdata   UCHAR   G_Powerstate;


xdata   USHORT  G_W_OldTime;
//xdata   USHORT 	G_FileCurrentIndex;
xdata   ULONG   G_Mpeg_Status;
//---------------------
//type of storage used
//---------------------
xdata   UCHAR   G_ucStorageType;
//--------------------------------------------------------------
//command and data buffer of control pipe and bulk in/out pipes
//--------------------------------------------------------------
xdata   UCHAR   G_ucCtrlCommand[K_CtrlCommandSize];
xdata   UCHAR   G_ucCtrlData[K_CtrlDataSize];
xdata   UCHAR   G_ucStorCommand[K_StorCommandSize];
xdata   UCHAR   G_ucTempData[512];  // WWMP3
xdata   UCHAR   G_LCDTMoutCnt;
//-----------------------------------------------
//storage interface N belongs to which USB class
//-----------------------------------------------
//xdata   UCHAR   G_ucPktStorIntrf; //current packet belongs to which storage interface
//-----------------------
//pointer to data buffer
//-----------------------
UCHAR   *G_pucCtrlDataPointer;  //for both CODE and DATA area
xdata   UCHAR   *G_pucStorDataPointer;
//--------------------
//L1 Global variables
//--------------------
data   BIT    _USBCardST1, _USBCardST0;
//xdata   ULONG   G_BulkSize;
//xdata   ULONG   G_BulkOutSize;
//xdata   ULONG   G_BulkDRAMAddr;
//xdata   UCHAR   G_LastBulk;
//xdata   ULONG   G_BulkFlash;
//xdata   ULONG   G_BulkFlashAddr;
//xdata   ULONG   G_BulkSRAMAddr;
xdata	ULONG	G_AccessRevBlockPhyAddr;									

//--- check card remove or plug in ---  @shawn@20030820
data    bit     _Card_Event=FALSE;
//xdata   UCHAR   Polling_Card;								


#if ( SIMULATE == 1 ) // WWWW
xdata   UCHAR   G_ucStorData[K_DMA_MaxSize];
#else
xdata   UCHAR   G_ucStorData[K_DOS_SectorSize] _at_ 0x1400;    //ada@0118
#endif
xdata WORD G_SMC_ReservePhyBlkAddr[K_NANDF_TOTAL_RESERVE_BUFFER];


UCHAR   code    DSP_MenuMODE[] ={KDSP_MP3_MODE, KDSP_DVRD_MODE, KDSP_DVRE_MODE, NULL};  

code  UCHAR     G_Battery_GroupValue[][4]={{2,3,4,5},{9,10,11,12}};
#if  (Auto_Repeat_OPTION==1)
data  bit       _G_StudyFunc;
unsigned char xdata G_StudyRepTimes;
unsigned char xdata G_VOXSensitiveLevel;
unsigned char xdata G_VOXDetectTime;
#endif

extern data    BIT     _GUSB_APOutReady;
extern data    BIT     _G_DSPgoSleep;

extern data    BIT _GUSBInPVID;
extern code    UCHAR   K_DeviceDescriptor[];
void 	Initial_LCD_DisplayMessage(void);
void 	Storage_CardDetection_InUSB(void);

//=============================================================================
//Program
//=============================================================================
//-----------------------------------------------------------------------------
//main
//-----------------------------------------------------------------------------
void main(void) USING_0
/*++

Routine Description:

        main routine

Arguments:

        none

Return Value:

        none

--*/
{
        XBYTE[0x2002] |= 0x01;   // DSP initialize --Reset !!
        XBYTE[0x2100] = 0x0f;   //SRAM enable, rompage/rampage enable

        spca757main();
}

//-----------------------------------------------------------------------------
//spca757main
//-----------------------------------------------------------------------------
void spca757main(void) USING_0
/*++

Routine Description:

        main routine

Arguments:

        none

Return Value:

        none

--*/
{
//	UCHAR i;



        XBYTE[0x2100] = 0x0f;   //SRAM enable, rompage/rampage enable
//        XBYTE[0x201a] = 0x0f;   // Disable GPIO[1..3],GPIO 0,4,5 is Still Useful in MaskCode
        XBYTE[0x201a] = 0x2f;   	
                          
	G_UI_USBConnect = K_UI_USB_DISCONNECT;		// Another Definition for MSDC's Subroutine
//	EA = 0;
//	EX0 = 0;

	INITIO_Initialize();
	//==initialize parameters==//

	


/*
//	G_FileCurrentIndex=1;		// Default the File index is 1

	if(G_USR_DirList[G_UIMODE].totalFile)
	{
		G_FileCurrentIndex = 1;
	}else{
		G_FileCurrentIndex = 0;
	}
*/

//	G_btSoftwareResetFlag = 0;

	G_end_of_file=TRUE;    //..
	_GPlayPause=FALSE;     //..

	//================
	//xyq add 021226
        //================

	G_SPL_BlinkTimer=0;//xyq 021116
	G_SPL_BattBlinkTimer=0;
	G_LED_Blink_On_Timer=0;//xyq 021218
	G_Battery_Detect_Timer=0;//xyq 021218
	G_USB_PlugInTimeOut=0;

	_G_DispUSBBSY=0;
	_G_Disp_PC=0;

	_G_Storage_Full=0;
	_G_UIPostError=0;
	G_AB_Cnt=0;

	L10_disp_Count=0;

	Variable_init();

	
	#if	(MLUN_OPTION)
	if (G_MLUN_Card_Present)
	{
		_USBCardST0 = TRUE;
		_USBCardST1 = TRUE;
	}
	else
	{
		_USBCardST0 = FALSE;
		_USBCardST1 = FALSE;
	}
	#else
	_USBCardST0 = FALSE;
	_USBCardST1 = FALSE;
	#endif

	_G_Battery_ChargeFull=0;

	_G_USB_Setup_Ack=0;
	_G_USB_Setup_Interrupt1=0;
	_G_USB_PowerPlug_Interrupt=0;

#if  (Auto_Repeat_OPTION==1)
	_G_StudyFunc=0;
	G_StudyRepTimes=3;
	G_VOXSensitiveLevel=5;
	G_VOXDetectTime=5;
#endif

	MAIN_LockLoop();
}

//-----------------------------------------------------------------------------
//MAIN_LockLoop
//-----------------------------------------------------------------------------
void MAIN_LockLoop(void) USING_0
{
//#if (MaskCode_OPTION==0)
//	while (G_btSoftwareResetFlag == 0)
//#else
	while(1)
//#endif
	{
		MAIN_PreDpc();
		if(G_Powerstate==0x02)
		{
			_UIEvent = FALSE;
		}
		else
		{
			MAIN_EventPreDpc();
			//==Get Key Event==//
			UI_PreProcessor_scan_key();
			//==Please reference to UI implementation note==//
			UI_EventPreDpc();

			UI_Processorstate_transition();

			UI_EventPostDpc();

			//==PLAY&REC==//
			Audio_CoDec();
			MAIN_EventPostDpc();
		}
		if(SPL10_Disp_Event)
		{
			LCD10_Disp_AllIcon();
		}
		MAIN_PostDpc();
	}
}


另一個重要因素就是因為這樣的系統已經越來越複雜了,我們團隊包括大陸那邊

的工程師,已經不是一兩個工程師在維護這個系統平台,你就得用高階語言開發

環境來讓系統開發容易上手啊。

所以從這個歷程,大家可以簡單地看到一個技術進步的演變。

當然當產品市場需求越來越複雜,也隨著科技進步也會帶來硬體資源的進步。

慢慢的:你可能不只只想用一般C 語言的基本語法來做為你產品系統平台基礎。

自然而然的,你就會慢慢地導入更先進、更方便的開發平台了。

---

創業結束後,我又回歸工程師的人生歲月,這幾年除了撰寫一般MCU 韌體之外,

也寫不少PC 端的APP 應用軟體。自然就會受到Visual C++ 的影響。我開始在

我的韌體開發過中,慢慢想導入 C++ 的語法了。至少對我來說:在硬體支援

豐富的資源之下,我再也不用很辛苦地在記憶體變數宣告中,辛苦地去斤斤

計較容量問題。目前都已經大量使用結構化的資料架構:


	
//==
/* sht4x struct */
typedef struct SHT40_U16
{
			uint8_t		Reserved0:8;				// SHT4x Reserved 0
			uint8_t		Reserved1:4;				// SHT4x Reserved 1	
			uint8_t		Reserved2:3;				// SHT4x Reserved 2
			uint8_t		bConnected:1;				// The status of SHT4x Device connect
} SHT4x_U16, *pSHT4x_U16;

typedef union SHT4x_Status
{
   uint16_t SHT4xU16;	
   SHT4x_U16 SHT4x_Dev;
} SHT4x_Status;

typedef struct
{
  SHT4x_Status DevStatus;	            /* sht4x sensor status */
  int32_t Temperature;								/* sht4x Temperature */
  int32_t Humidity;                  /* sht4x Humidity */
}sht4x_UsageTypeDef;

//===

----

	
		if(sht4x_Usage.DevStatus.SHT4x_Dev.bConnected)
		{
	        /* Measure temperature and relative humidity and store into variables
    	     * temperature, humidity (each output multiplied by 1000).
      	    */
       	 int8_t ret = sht4x_measure_blocking_read(&sht4x_Usage.Temperature, &sht4x_Usage.Humidity);
       	 if (ret == STATUS_OK) {
            printf("Temperature: %0.2f C, "
                   "Humidity: %0.2f %%RH\n\r",
                   sht4x_Usage.Temperature / 1000.0f, sht4x_Usage.Humidity / 1000.0f);
       	 } else {
            printf("error reading measurement\n\r");
       }		

//===

----

當然啊,如果你是科班念軟體資工畢業的,又受過一定程度的實質產品計畫歷練,

對你們來說:這再也不過是小菜一碟而已。但對我們這種非科班出身的,又一路

從組合語言走來的老工程師們,又是另一種感觸。

---

那我們就來談談這個議題:技術的深度及廣度。

以我自己的職場技術發展軌跡來說:一路順著產業技術升級,慢慢地從傳統組合語言

練起,再到MCU 的 C 語言平台。其中還專注著 USB 周邊技術系統發展。一個人走過

這樣子歷練,也不算甚麼?其他絕大多數的工程師皆是如此,至少我們還是得考量到

現實生活啊:柴鹽油米醬醋茶啊。在職場上,技術沒辦法換來薪資所得養家活口。

早就臣服於現實壓力,轉換跑道去找飯吃了啦。根本不用再談技術的深度與廣度。

那我一路從傳統MCU 的IC 設計公司寫韌體搞系統,那我到底是要好好地往這個

領域的"深度"往下走呢?還是藉由之前累積的經驗的,去廣結善緣的往"廣度"走

這就牽涉到時勢與市場環境與潮流改變綜合因素。這畢竟都不是我們自己單方面

堅持就可以。這無非就是從市場獲利能力來看:不管是就業市場或開公司創業機會。

其實也蠻容易從一個簡單的趨勢現象與道理觀察出來的。

越是越大的公司,往往就是專注在某個領域市場的核心技術。譬如:蘋果就是搞

手機應用平台、聯發科技就是得專注在手機晶片領域,而Intel 就是處理器發展。

華碩宏碁就是筆電或桌機系統。因為他們唯有專注屬於自己在市場領導地位

產品上,才能一直維持公司的獲利能力。而小公司呢?為了能在市場存活,

一開始就得要在系統應用領域,尋求獲利機會。你總不能說:我創業開公司,

就是要作手機晶片,去開一個史上獨一無二的SOC 晶片、或是我想做個市場上

某個應用領域的技術領導品牌:像是工控領域的台達電、儀器設備的Fluke 等。

雖然有時候:你會笑人家台達電的馬達伺服控制器也不怎樣,但你打算花多久?

花多少資源的想把人家拉下舞台?你有多少資源跟別人拚?

更何況最重要的是:你也別忘了,整體產業的技術趨勢也會不斷的增長提升。

就像我們之前說的:是啊,寫8051 組合語言看起來很厲害,也非常有執行效率,

但問題是:人家後來整個MCU 的核心效能、周邊資源一直整合,隨隨便便

套個某個應用領域市場的標準函數庫,就比你在家裡蹲個三、四年還厲害了。

你還在跟我說:這個技術領域我已經蹲了幾年了,整天就在網路上吹自己多

堅持,那很簡單啊:請問一下用你的技術,可以很簡單的整合周邊系統成為

一個非常簡易上手又穩定強健的系統產品嗎?

---

前幾天有人在社群媒體上討論:可不可以在Arduino 平台上實現類似 PLC 的

語法產品概念?其實這個議題很簡單的回到產品市場現實生態上。PLC 已經

在技術的應用市場歷史裡,走過多少"深度"發展?也幾乎綁住一切相關應用

市場。你只是想做個程序控制的控制平台:有很多既成熟又穩定PLC 模組

任君挑選,還可以搭配許多各式各項的HMI 模組。而這些有技術深度的

產品也幾乎就是我說的:絕大多數都是有豐沛資源的大公司所掌控。

不是你不能去做這方面的深度發展:而是你要花多少時間與金錢資源完成?

你自己給自己的時程時間表在哪?你每一筆投入的資源,有屬於自己的

Milestone (checkpoint) 嗎?自己當老闆的就不用 Review 嗎?😷😷😷

搞技術真的不要搞到腦袋頭殼壞去吧?自己瘋,也用不開公司找員工來一起

瘋吧?你一年不醒,兩年不醒...但需要"柴鹽油米醬醋茶"的員工會醒啊。

所以當我創業走到一個關鍵的時間點(milestone/checkpoint)時,我就告訴我自己:

募資開公司已經無法從技術的深度去獲得市場成功機會時,我就得改變職場

的經營策略:要以技術的廣度,讓自己好好得活出工程師生涯的下半場。

當然也非常高興得趕上所謂"經濟平台"時代的趨勢。(這個概念可以參考上一篇

文章的留言討論處)。因為我們不是檯面上那些可以創造經濟平台的大公司:

甚麼是MCU 應用市場經濟平台的大公司?你看人家ST 目前的32 位元MCU 

的市場地位。就算要搞MCU + 驅動模組應用方案,也是由這些經濟平台

公司所主導的。因為這本來就是他們在專業技術深度的核心價值啊。

也真的不要急於看到甚麼就得想技術深度走,因為市場與技術趨勢會

再改變與升級。這些掌握經濟平台的大公司會一直專注地投入資源來維護

他市場領導地位的,我們就只能懂得利用這些資源平台為自己創造機會。

--

我們當然也知道我們在這個經濟平台市場趨勢下:暫時也只能依附在經濟平台

下的投機者。這也是一時沒辦法可以馬上改變的現況,但至少我們自己要了解

這個趨勢與機會。在技術領域裡:有很多在技術平台上有深度的資源可以供你

使用,你就得要好好把握這些經濟平台去架構屬於你的核心價值:

像我自己本身:光搞MCU 的韌體是不夠的,還要需要整合一些產品市場需要

的平台:APP 應用環境與相關的系統測試驗證平台,一直延伸屬於你的技術廣度。

說真的啦,有機會我也想寫寫手機APP 啊。

但這方面不像PC 端就只有Windows 系統平台,有 iOS 及 Android 啊。

當然如果我有資源(資金),當然也不用自己做啊。但在沒有掌握穩定的

一席經濟平台上的地位時,也只能暫時得如此,但真的要記住一個現實

事實:在目前這些你所掌握的資源環境裡與市場經濟平台發展過程中,

到底我要的是技術的深度?還是技術的廣度可以讓自己未來有更好的機會?

----

結論感想:搞技術深度喔?就去找間技術或產品相關公司上班吧。(學校?)

要能長長久久的存活在工程師的技術領域裡,也就只想辦法拿本身技術的廣度,

來當九命怪貓吧。都既然也已經在MCU 系統領域裡,做那麼多年了,經驗累積

也有一定的技術廣度了,何樂而不為呢?何必糾結就非得做甚麼產品技術

才是你的真愛?年紀一大把了,就不要像年輕人一樣的被愛沖昏頭了吧。

25 則留言:

  1. 追求深度和廣度真的一直是工程師職涯的抉擇,年輕時覺得自己會得很多,但深度好像不夠,一直碰不太到底層,除了上一家公司,都在GUI及AP層打轉比較多,其實前不久也還是跟同學討論這個問題,他是勸我還是要立一個停損點,如果真的無法摸到底層到一線IC廠,就要找別得出路,畢竟大家都不年輕了,過而立之年了。雖然蠻遺憾可能無法繼續往追求深度的道路走,不過追求技術廣度也許是一條不錯道路,也能換來一些額外機會,像之前在轉職到網通業前是寫iOS APP,意外透過前同事引薦當一家叫誼騰動力公司的顧問賺了一些顧問費,也許這就是前輩說的把技術變現的路,當個技術顧問之類的。

    回覆刪除
    回覆
    1. 很好啊。
      會寫手機應用軟體,就是一種投資報酬率很好的技能。
      因為不用壓太多硬體設備成本,
      雖然在台灣公司老闆眼裡,寫軟體的沒有做硬體的價值感。
      但也是因為如此,才有更多斜槓的機會啊。
      因為軟體的東西,不像硬體,大家拆著看,很容易被抄襲,
      也很容易給原來公司留下把柄...軟體APP 跑起來,
      誰知道這是誰做的?用甚麼開發平台或內容之類的。
      只是要接軟體的案子,就只能很低調的、隨緣而已。

      至於誼騰的顧問費,有收到就好,能不能還有後續?
      就看緣分了囉?你說是不是啊...😁😂😂


      刪除
  2. 技術的廣度是用來探方向是否合理正確,因為自己看出去不一定對。
    技術的深度是符合自己興趣又想要有成就的。
    中間會有很多技術結果評估,我就記在數位筆記上。
    當時還未採用數位筆記,所以就貼在Blog上面,方便未來時機到再次評估用。
    事實是:手機APP起來了,它的重要性比C++重要的多,所以我又去研究MCU如何和手機聯合

    回覆刪除
    回覆
    1. 技術的廣度是用來探索方向,這樣子講也沒錯啦。
      我說過了:年輕時,想學甚麼,有甚麼困難的呢?
      我學校剛畢業時,對電腦動畫也非常有興趣啊。
      後來就踩煞車了。
      搞技術,我相信只要你對於工程開發有興趣,
      基本上,要談廣度或深度都可以啦。
      至於技術的深度,可不可以找到屬於自己的成就感?
      這點就真的見人見智了,我弄個機車數位點火器,
      可以變現,也可以參展拿個獎牌,我就滿足了。
      但在別人的經營績效考核角度上,可能不怎麼樣。
      這點我也非常認同,因為原本也以為可以在那個領域裡,
      不斷的深根茁壯....但我們也不可否認的:
      不只那個技術產業市場在變,就連相關技術走向也在變。
      沒有足夠的資源可以供你順著產業市場發展深根時,
      那已經不是你關起門來,蹲著深耕就可以有所成就了啊。
      興趣,當然還是興趣啊,但就不要有那麼大的壓力啊。
      或是真的要換個腦袋或角度來思考了啊。但肯定就不是
      原來那一種宅男工程師的那個德性的搞一輩子吧。😁😂😂


      套著這兩天那個政大商學院副院長買馬莎拉蒂的新聞:

      獨家/靠0050買瑪莎拉蒂! 揭密財金教授「躺著賺」心法
      https://fnc.ebc.net.tw/fncnews/headline/177592

      剛好驗證我一直強調的概念:
      想技術與營收兼顧,很好啊~你就去學校當老師啊。
      有個穩定的固定收入,又可以讓你學以致用,
      只不過:背後也有很多不為人知的鳥事啊:

      李清志/提前退休的理由
      https://udn.com/news/story/7340/8273071
      "雖然熱愛教學,但我也是個喜愛自由、討厭體制的人,
      無法忍受現在教育單位沒有意義的開會、填表格、評鑑、
      積點數等等行政作業,我認為這些事其實是在浪費我的生命..."

      是啊,~只要是單位組織團隊,就得要稽核考察管理啊。
      要不然,別人也會說三道四的啊。
      我也只想好好當個可以整天搞技術的工程師啊,
      我也不想接部門主管,有太多的行政Paper Work 的雜事啊。
      這些事情都不是大家表面所想的那麼單純簡單的啦。

      至於手機APP,應該換個說法啦:行動通訊平台,
      因為還要包括車用平台等,我當然也知道未來會比
      PC 個人電腦有前途未來啊,那就更不用說:
      背後那個龐大的雲端資料運算處理中心啊。
      大家都懂,不管是搞技術的、或市場分析投資理財
      等專家。只是我們手上有多少資源(時間與金錢),
      可以讓我們去參與而已。大家就努力加油吧。

      刪除
    2. 我想我知道問題在那裏了。我之所以什麼都評估,每次評估好都寫成數位筆記,以方便後面尋找再整理,這是另一個退休企業家要我做的。我可能不知不覺開始變成習慣。我會去請教他一些問題,大部分都只得到方向。然後他教我什麼事都要懂一點,因為企業上百人上千人什麼狀況都可能發生。我本來覺得這樣不就什麼都學,是不可能學完的。但幾年下來我發現方向錯了。學的不是事情本身,而是事情的模型,了解事情前因後果,類似的事很情就可以上手。這是他管理企業的方式,我照他的方法做,確實是有用的。

      刪除
    3. 不錯。
      我知道很多工程師的性格都有點自戀的只相信自己。
      就算有人願意分享一些經驗或見解時,
      工程師有時都會覺得人家是意有所指地指責他的缺失。
      聽不進耳朵的,可能就是對你的忠言。

      過度的相信自己的信仰:唯有擁有技術就是崇高的理念。
      本來有多事情,都不是絕對的對與錯,
      也不可能可以給你一個明確的方向與方法。
      誠如你所說的:就是一個方向或是一個模型與邏輯推理原則。
      如果年輕時,無法做到廣納建言,調整思考與做事的原則。
      越老時,就越難改進與修正...就越會相信自我。
      惡性循環的結果就是我所說:
      工程師一生最後窮到只剩下一些自認一身功夫在身而已。

      至於有沒有用?就你以前提過的那位8051 組合語言大師一樣。
      躺在安寧病房裡,還是沒有人看得懂他的程式。
      也沒有人有興趣想去了解吧。

      這是我們身為工程師們所需要不斷的反省與修正的。
      活出自己有尊嚴又自在的工程師人生。

      刪除
  3. https://tw.news.yahoo.com/uscaseai-011618855.html
    這件事在AI圍棋比勝人類時我就查過了。當時就確認沒有版權。所以我就提出一個極端案例,萬一有人用AI仿某產品的操作,經過訓練生成出來的產品又拿去賣,是不會侵權的。然後現在AI可以產生程式,所以我設定的時機也就是到了。

    回覆刪除
    回覆
    1. 我寫太少了。因為這個現象,AI公司也知道,也就是原先很多專利卡住的都有機會利用AI繞過去,變成先佔先贏。產品到時又重新洗牌,只有AI平台公司是贏家。

      刪除
    2. 今年諾貝爾物理獎公布了。
      得獎的內容就是跟AI 有關。

      "AI教父獲諾貝爾物理獎,這會不會「不夠物理」?"
      https://www.techbang.com/posts/118799-is-it-reasonable-that-the-godfather-of-ai-won-the-nobel-prize

      這個趨勢是無庸疑置的,他也會深入到每個生活的應用領域,
      會改變我們研究創造或生產管理等方面(包括你所說的智權)。
      為什麼各個領域的學者、公司企業要不斷的研究評估。
      當然大家也都看到了啊。
      不是我們不願意去參與或學習,就你所說:你看得到,
      公司企業也看得到啊。AI 公司更是快馬加鞭啊。
      我們就只能趕快的調整自己方法與思考模式。
      從中間去找出一塊可以利用AI 資源與我們本身經驗的
      資料庫,來為自己創造未來的機會。
      其實網路上已經有很多AI 資料庫的平台了,
      包含那些開源平台也都是,我們現在也已經開始無形中
      使用與貢獻充實這些資料庫了。
      也已經由不得你的願不願意決定與否了。

      刪除
  4. 就小弟所知,Rust才是未來韌體開發語言的趨勢,他有解決C長久以來的問題-記憶體安全,而且Microsoft,Amazon...一堆大咖投資給該團隊或直接在OS內支援(如Windows, Linux)

    https://www.bnext.com.tw/article/75788/rust-code?

    用Arduino做PLC以小弟的觀點來看根本沒啥好談的,很多人只看到很好玩,很便宜,但完全沒考慮到PLC是在工廠內要用個5-10年以上,你能保證供貨5-10年?
    你的品質,編輯軟體成熟度可以跟三菱或西門子等老字號比嗎?教育訓練這塊更是很多搞技術的人完全沒想過,好像認為大家都會乖乖學你那套新東西,從老闆的角度來看
    人跑了我要從哪找?最愛山寨的對岸也是用STM32做山寨PLC直接套三菱的軟體

    回覆刪除
    回覆
    1. 基本上,要用哪一種語言發展公司產品,坦白說,
      老闆是不會管你們研發單位的,程式寫一寫有問題,
      效率不好?
      那就請你們自行免費加班、也不要額外開銷把問題解了吧。

      滿街能招來的工程師絕大部分都會C/C++,
      你跟老闆說:我們要花時間學習與轉換以外的程式語言。
      你跟我說:台灣有幾個老闆可以忍受你這種藉口、說法?

      Microsoft、Amazon ? 人家大公司有資源,而且老外
      也懂得尊重寫程式的人員,所以你對Rust 的見解我同意,
      但如果在台灣哪家公司可以實現這件事,你再跟我分享一下。
      我肯定要好好的膜拜一下這公司的老闆開明作風。😁😂😂

      至於 PLC 的工程與市場問題,這就是回到工程師的心態了。
      真的過度膨脹自己的能力與想法了。
      別的不說:就簡單的把自己搞完的技術,有系統地對公司
      內部進行教育訓練時,道理是一樣的:老闆的看法跟你工程師
      的看法是否一致?
      往往會有這些想法的人,都是那些小公司,老闆就是搞技術的人,
      就整天異想天開的覺得:自己的技術不得了了,肯定可以掀起
      市場革命的,我會一統天下這些傳統企業的這些老產品....
      就跟電動機車的G 公司老闆一樣,只要我一出江湖,這些
      做油車的傳統機車廠肯定會吃鱉,然後每一家就準備倒閉收攤。
      結果:最後就是人家還是活得好好的,是你自己先掛了。😁😂😂

      那些山寨的東西,不是不能做,也不是沒有市場,
      但人家大公司,大企業投資弄工廠,搞生產線,不會缺
      那幾塊錢的啦。(況且現在那些PLC 大廠成熟的東西,也
      貴不到哪裡去啊。) 搞山寨的產品市場,也不光只是技術
      而已啦。還是同樣存在市場策略問題。

      搞產品技術終究有一天你可能會追上大廠,但然後呢?
      就靠嘴巴整天吹就好?你總得還是要透過業務市場去推啊。

      我們就看你怎麼先說服你的市場業務人員?
      你就不用再出資源?公司的市場業務人員不用管銷費用?
      你想賺個5~10% 就好。(你覺得很好賺~) 但人家市場業務
      通路也要抓個5~10% 利潤....(還沒算到工廠生產備料成本)
      最後,東加西加...加個 30~40%,你還能跟大廠的報價比嗎?
      是不是最後又是笑話一則?怎樣?你要罵業務市場通路人員
      無良心?你最聰明、最厲害?老闆是笨蛋,不會聽你的?

      人年紀大了,就不要老是那麼天真了啦。
      市場,世界會長成這個樣子不是沒有道理的啦。
      GodSpeed 你同不同意我的看法呢?😁😂😂

      刪除
    2. 小弟就是靠C++維生的,C++有分C++98,C++11,C++17,C++20等n個版本,來面試的人考筆試,我還得在考卷上特別註明是哪個版本,就算如此還是有人寫錯...基本上firmware還是C,C++太混亂了

      C/C++之所以還能在路上找到一堆,那是因為歷史包袱太大了,非得找人來維護,但對於年輕人(不包括我)來說,如果讓他賭Rust賭對了那就不得了了,事實上104上還是找得到近數十間公司在找會Rust的人,尤其對於新創來說沒有包袱,更是可以大膽採用

      至於PLC,本來沒有暴利可圖,工控要導入,驗證一樣產品,那個時間之長,量又少,我是不知道哪個人想不開會想去玩,再來講一個重點,寫PLC的人大多是傳產,薪水很低,而且上游插旗都插滿了,不講三菱西門子,國內永宏,台達電,豐煒這三間就插滿旗子了,這三間起碼在市場蹲20年了,而且要便宜,這三間也有超便宜的機種,會想弄Arduino PLC的人我覺得這人應該不是巷子內的才會在那座夢吧


      刪除
    3. 你說對了:有很多人事物都是有包袱的。
      搞軟體寫程式也是,公司若一開始就用C/C++,就不容易改。
      你所說的那些使用Rust 的公司,難道也沒有嗎?

      所以啦,我現在看事情就比較平常心,真的也不會說:
      哪個程式語言比較好?誰的技術有多好?哪家公司就比較好?

      反正啦,只要人家可以順順利利、平平安安的上班賺錢就好。
      一家人可以幸福美滿快樂就好。

      另外關於招人考寫程式這件事,我前一陣子不知道在哪篇
      文章中,看到好像一位國際知名的程式軟體大師,就非常反對
      招募用考程式這種方式,如果是這樣子的話:
      我這輩子應該就沒機會找到寫程式的工作了,就算自學個
      幾年,我也不知道我自己可不可以過得了那一關。

      或許是不同的公司有不同的看法吧。至少我在園區幾家
      大公司就真的比較少聽到,我想像聯發科要找台清交的
      畢業生,應該只是看看學歷或在校成績,應該不會還要
      搞一套入職考C/C++。在這些公司裡,你寫程式程度不好,
      也趕不上研發團隊的進度時,應該也不用很久就會陣亡了吧。

      如果:你真的很努力地花時間可以趕上研發團隊的進度,
      我想那個積極的態度是比你C/C++程度好壞還重要吧。
      可能就你說的:小公司賭不起人員淘汰率吧。
      所以我有時候會覺得:有機會去人家大公司待著晃晃看看,
      也是一種不錯的經驗體會的。

      關於類似PLC 的這種成熟產品市場,都是可以供大家一個
      從技術以外的觀點來思考一些:產品研發到底是要從技術
      角度呢?還是從市場行銷或使用者角度?
      市面上有很多這種產品東西。像我做的數位CDI,滿街都是了。
      有各式各樣,有簡單便宜的難以想像,但是我還是有訂單。
      餓不死,當然也賺不了大錢啊。你說:我還會一直投入資源,
      或拿這種技術出來吹嗎?那如果還有別人想出來做類似的產品。
      喔~很好啊~我也不會唱衰你,你就慢慢的自己孵吧。
      另外,我最近才知道:除了知名的 Raspberry Pi 外,
      市面上還有一個 Banana Pi,他是由我以前公司的一位同事
      在鴻海時做的,他後來把這個東西交給大陸人之後,就離開了。

      他私底下說:這個東西還是真的比不上Raspberry Pi 的啦。
      主要還是在於市場主流資源的啦。其實道理也都是一樣的。
      這些都不是你工程師個人或是侷限在一個資源有限的小團隊裡,
      長期堅持或努力就可以了。
      初期努力,那是一種幻想與夢想,從學習的角度來說:很好。
      但五年,十年,二十年...那你到底是在做甚麼?
      時代環境會一直改變,你原本覺得有技術市場機會的,
      是啊,可能真的有市場機會的,有資源別的公司與團隊,
      隨時都可以直接超越你,更可以狠狠的把你甩到很遠之處。

      屆時就你所說的:就只能困在一個狹小的小巷內,
      在社群媒體群組裡,討討按讚數,抱團取暖而已。
      有些人事物,如果我們可以跳脫原來的框架想想,
      或許都是一些很好正面的人生導師啊。

      刪除
    4. MTK可以找最優秀的畢業生,訓練個半年沒貢獻都沒關係,搞不好還可以一次錄取一堆,試用期過後還可以淘汰掉一堆不適合的,反正公司資源多名氣大可以慢慢玩,我也待過夠規模的公司,報到前幾個月就是上一堆課,甚至還有電話禮儀

      但你說小公司可以這樣玩嗎?當然要找即戰力,我也不過是希望來面試的人對程式語言有個起碼的熟習度,也就是你平常有在用就大多答得出來,也沒要你考100分,有個5,60分不過分吧?

      再說我面試過很多公司,很少沒筆試的,大部分考得還比我考別人的難,外商,防毒軟體公司,高頻交易這些我去面試過都有考筆試,甚至誇張到考一百題硬體軟體包山包海的都有

      要不要考筆試也有其他軟體大師認為一定要考,例如Joel Spolsky,好比錄取魔術師,你不會要求他變兩個戲法瞧瞧?而且根據我用人的經驗,筆試成績還真的跟表現正相關,就算MTK好了,看學校成績單,裡面不少不也是筆試成績?

      至於Rust,當然也有他的包袱,但C/C++的包袱可能是3~40年,Rust頂多幾年,再說C/C++不好的包袱可多了,Rust也是因為把這些不好的包袱解決才能得到這些大廠的青睞,C/C++工程師可能把debug pointer當成吃飯的密技,但對於Rust來說只要能編譯成功幾乎就沒這方面的問題,只要Rust能存活應用逐漸變多,若干年以後翻轉是很有可能的,當是年輕人才有本錢去賭就是了

      微軟已經在核心嘗試Rust了(別忘了他一向不愛捧非自家的程式語言)
      https://www.techbang.com/posts/106699-ill-get-it-after-the-rest-of-the-article-today-instead-of-c

      刪除
    5. 現在因應高速發展的資訊軟體功能,未來還有甚麼軟體架構,
      都很難說了,那你說:學甚麼比較有未來?
      只要有人願意付薪水給你的就可以了,而且未來還可以不斷
      的加薪比較重要,要不然就跟以前學組合語言一樣:
      一開始也有人願意付薪水給你,但後來就慢慢的沒啥加薪機會了。

      未來萬一大家都用AI 幫忙寫程式了,學甚麼語言就沒那麼重要了。

      MTK 或其他一線大公司所找的台清交一流畢業生來上班,
      用甚麼軟體平台,對他們來說都不是很難的啦,
      沒一個月內上手的,大概就準備要丟履歷去找別的工作了。
      那些頂尖的學生,在學校念書考試就像學霸一般的,
      你認為念書學個語言程式碼,對他們來說:真的很難嗎?
      我是老闆,根本不用擔心這種事啊。

      我說過了,就只有我們這種苦讀出身的工程師,挑選可以
      安身立命的程式語言技巧或謀生技能,就得戰戰兢兢的,
      因為一投入下去的代價很高,賭不起這種風險。
      對他們這些公司的領導來說:要說服我的不是甚麼程式語言?
      而是我老闆付了你們這些人高薪之後,你們要跟我說:
      我的產品如何在世界激烈的競爭市場中,如何勝出吧?

      看看人家現在 tsmc/Nvidia/AMD/Intel/Qalcomm/MTK 或
      Google 這些一流國際公司殘酷的競爭態勢時,
      就知道甚麼是未來?

      至於我們這些沒機會站上這些舞台的工程們來說:
      就是要務實一點:誰付我薪水,未來還有機會加薪,
      最好還可以幫我支付勞健保到退休...我就阿彌陀佛了,
      感謝上帝囉。

      刪除
  5. "這些東西不要再學了,這是我們那個年代的宿命", 工作一段時間之後的工程師才會懂得這句話的重量. 尤其是IT跟EE產業的.

    回覆刪除
    回覆
    1. https://www.tiobe.com/tiobe-index/
      組合語言仍在前20名上面,為何不要再學?
      工具本來就有限定,只是IT換得比較快,因為進展快。重點是趨勢在那裏,而不在於工具本身。如果只是追流行,自然不知道工具學了要怎用,只是糊口。
      IT的最基本就是碼,組合語言就是最基本機械做事的方法,原理要學,但不可鎖定在單一目標上。

      刪除
    2. 對不起囉。
      如果我還在MCU 設計公司上班的話,那肯定還是會玩組合語言的。
      但現在要我去用組合語言為主來開發系統產品,
      除非真的有老闆或金主付我薪水強烈要求我用組合語言,
      我也不反對啦。我這種年紀考慮的就真的只有餬口而已。

      今天中午剛好跟我以前一位老同事吃飯,
      就是我上回提到後來去了鴻海搞 Banana Pi 平台的那位。
      他離開鴻海之後,有個因緣際會去搞了一年多Python 。
      像我們這種年紀,學得有點辛苦,結果今年上班的公司收了,
      領了資遣費,也領了幾個月的失業救濟金...
      幸好最近有接到工作通知了....做甚麼?用甚麼程式語言?
      不重要了...還是替他感到高興的啦。

      刪除
    3. 這個組合語言,有99%討論的是WebAssemble。是用來加速瀏覽器去執行Game的方法。也就是瀏覽器內建一個byte code直譯器就直接執行使用者的檔案。並不是在MCU上執行。但它有一個副專案,就是再轉成ARM的機器碼。因為windows on ARM開始變得流行,本來從VM(虛擬機)上執行也有可能轉成實體CPU執行。它算是IOT的一部分。我認為若是edge IOT未來是可以利用WebAssemble載入去執行使用者程式。

      刪除
    4. 是...是...是...
      如果架上組合語言就是為了某些系統使用需求,
      我相信都是可以接受到,就像我以前在MCU 設計公司上班,
      為了確認MCU 每條機械指令都可以準確執行無誤,
      當然就得整天寫組合語言啊,但你要把MCU 賣給客人市場之後,
      你還要客人用你的MCU 還要這麼搞?那不就玩死客人,
      也玩死自己嗎。所以終究還是得看產品市場的目的吧。

      程式語言都是隨著市場需求不斷的修正與演進的。
      當然也包括著相關組譯器與開發平台。
      這些都無非就是為了輕易推廣自家產品平台。
      是啊,高階語言效能是比較低啊,但人家現在硬體效能
      與周邊資源一直提升,當然就是為了彌補這些程式語言的
      缺失與不足之處。
      NVidia 為了推他們的顯示圖卡硬體架構應用在AI 系統上,
      人家也不得不重新開發一套 CUDA 平台。

      所以說啦:甚麼程式語言好用?流行?
      或實際一點說:學甚麼程式語言比較有前途(錢途)?
      就看每個仁自己的判斷與認知。

      也祝各位可以在每個人的工作生涯裡,都可以如魚得水的
      幸福快樂的寫程式,一套軟體語言技能可以永保安康的
      終身受用啊。

      刪除
    5. 我查了一下 Nvidia 的CUDA 平台的評價:

      NVIDIA 軟體戰略全面解析:建構未來幾年內難以撼動、既寬且深的護城河
      https://blog.finsight.investments/portfolio/nvidia-nvda-leading-software-ai-platform-continuous-innovation/

      這只有在國外軟體盛行的環境哩,才有辦法成形的。
      我們在國內就只能依附在大廠思維底下當個追隨者而已。

      刪除
    6. 回頭看STM32它已經平台化成功,對岸仿硬體,但利用其軟體工具,且不只一家。CUDA推出前5年,幾乎沒人在用,因為要改寫,好在它是C,我也從CPU C改成CUDA過。STM32知道平台化一定在軟體,第一件事就是推出HAL library然後自打自家的std library。HAL有了,再來買下IDE公司,推出STM32CubeIDE這個平台核心工具,再配合STM32CubeMX這個雲端平台界面。三者就是一整個平台化關鍵。一開始bug很多,多到STM32CubeIDE根本被認為是爛工具(和keil比),改到現在做ARM MCU的公司都不得不做類似的軟體工具,連硬體都想要去相容。這個是相容IP下單一廠商平台化成功的案例。

      刪除
    7. 接回主題。廣度是可以利用其他行業的手法,在成熟的科技背景下引入新管理方法的路徑。深度就是要調整本業去符合新手法的方法。

      刪除
    8. 不管是 STM32 的開發工具平台化,或是討論技術廣度來說:
      其實都在說明一件事:誠如你所說的平台經濟概念。
      這都不只是影響整個未來世界潮流,
      也當然會改變我們在技術開發的一些觀念上。

      AI︱發展神速超乎想像:AI雲端資金流入加速,今年預估可達790億美元!
      https://uanalyze.com.tw/articles/212107391

      投資就是代表著科技未來,更不用這些檯面上科技技術領域裡
      數一數二的大公司,當然人家也不是笨蛋。
      說真的:這個時間點,如果讓我再年輕個二、三十歲的話,
      我當然就不會再花太多心思在甚麼單晶片韌體、或引擎、馬達
      控制技術上面了。因為這些都已經是成熟科技技術了。
      藉由如何善用這些平台先進技術來幫我們引進新的技術管理方法。
      人家大公司 像stm32 這種有資金(去購併)、有豐沛的資源(結合
      全球各地科技技術人員投入),把他們的開發平台完善到各個應用
      領域裡,都可以輕易簡單上手了。

      人家是有錢可以去搞平台,我們就另一種人:真的要懂得如何
      利用平台了。如果沒有認清這一點:學甚麼技術?做甚麼產品
      開發或是講甚麼理想、夢想等,其實還是不夠務實確切的啦。
      這是我自己的感想啦。

      刪除
  6. 今天看到的日本冷氣大廠日立的故事:

    當代日本三大企業,賣家電賣到快破產?!日立如何從存亡邊緣浴火重生?
    https://www.youtube.com/watch?v=9QNb4qnOn1Y

    這麼大的企業,尤其在冷氣空調大廠技術成就,
    不管是馬達或相關技術開發。
    肯定就是業界的一等一的優等生。
    但這個故事就是告訴我們:這些技術到了一個
    頂峰之後,面臨的就是現實的市場競爭。
    單一技術頂峰是幫不了企業創造持續獲利的。
    唯有更積極的整合系統,搭配時代應用需求,
    引入更高端與市場應用端的技術,才能再創佳績。

    這也是明確的告訴我們:不是該做甚麼技術或甚麼事。
    而真的明確的告訴我們:在面對競爭與資源有效應用時,
    "是甚麼事,就不要去做了!"
    (應該更專注本身的優勢,趕快轉型去迎接下一個機會!)

    回覆刪除