過去這一兩年,我一直強調工程師的人生真的不要"窮到只剩下一身功夫"就好。
之所以這麼說:是因為隨著年紀的增長,也真的看得多,體會多。自然感觸就多。
因為都已經這麼一大把年紀了,你說:還有甚麼技術?就算沒摸過,至少從
產品市場上也多多少少也可以知道這些產品背後技術含金量到底有多少?
你說:真的要學,也學不完,往往最後都是卡在一個很現實問題:學了之後,
要如何變現?"上班領薪水?在公司就只做某些產品,你大概在專業分工下,
就只能專注在某項技術領域就好";"創業開公司?那你又不可能甚麼案子都接,
有些東西,你沒摸過,你就自己花資源(時間--工資與金錢--硬體設備)自己慢慢蹲。
蹲了也不一定可以真正的掌握(趕上)客戶或市場"。就算你想靜下心來專攻某個領域,
問題還是一樣:你公司的營運成本哪裡來?若要將技術成果產品變現成為常態收入,
那你也得要多花一點時間在生產銷售財務管理事務性工作上,多一點商業管理活動,
少一點技術研發工作。這些都是非常現實的問題。
所以我們就可以來討論你個人在你的工程師職涯規劃中:到底是技術的深度重要?
還是技術的廣度重要?在工程師的職涯中魚與熊掌可以兼得嗎?
最近跟 @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 ;============================================================================== --fw>
---
我要告訴年輕人說:這些東西不要再學了,這是我們那個年代的宿命。你還想:
用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 系統領域裡,做那麼多年了,經驗累積
也有一定的技術廣度了,何樂而不為呢?何必糾結就非得做甚麼產品技術
才是你的真愛?年紀一大把了,就不要像年輕人一樣的被愛沖昏頭了吧。
追求深度和廣度真的一直是工程師職涯的抉擇,年輕時覺得自己會得很多,但深度好像不夠,一直碰不太到底層,除了上一家公司,都在GUI及AP層打轉比較多,其實前不久也還是跟同學討論這個問題,他是勸我還是要立一個停損點,如果真的無法摸到底層到一線IC廠,就要找別得出路,畢竟大家都不年輕了,過而立之年了。雖然蠻遺憾可能無法繼續往追求深度的道路走,不過追求技術廣度也許是一條不錯道路,也能換來一些額外機會,像之前在轉職到網通業前是寫iOS APP,意外透過前同事引薦當一家叫誼騰動力公司的顧問賺了一些顧問費,也許這就是前輩說的把技術變現的路,當個技術顧問之類的。
回覆刪除很好啊。
刪除會寫手機應用軟體,就是一種投資報酬率很好的技能。
因為不用壓太多硬體設備成本,
雖然在台灣公司老闆眼裡,寫軟體的沒有做硬體的價值感。
但也是因為如此,才有更多斜槓的機會啊。
因為軟體的東西,不像硬體,大家拆著看,很容易被抄襲,
也很容易給原來公司留下把柄...軟體APP 跑起來,
誰知道這是誰做的?用甚麼開發平台或內容之類的。
只是要接軟體的案子,就只能很低調的、隨緣而已。
至於誼騰的顧問費,有收到就好,能不能還有後續?
就看緣分了囉?你說是不是啊...😁😂😂
技術的廣度是用來探方向是否合理正確,因為自己看出去不一定對。
回覆刪除技術的深度是符合自己興趣又想要有成就的。
中間會有很多技術結果評估,我就記在數位筆記上。
當時還未採用數位筆記,所以就貼在Blog上面,方便未來時機到再次評估用。
事實是:手機APP起來了,它的重要性比C++重要的多,所以我又去研究MCU如何和手機聯合
技術的廣度是用來探索方向,這樣子講也沒錯啦。
刪除我說過了:年輕時,想學甚麼,有甚麼困難的呢?
我學校剛畢業時,對電腦動畫也非常有興趣啊。
後來就踩煞車了。
搞技術,我相信只要你對於工程開發有興趣,
基本上,要談廣度或深度都可以啦。
至於技術的深度,可不可以找到屬於自己的成就感?
這點就真的見人見智了,我弄個機車數位點火器,
可以變現,也可以參展拿個獎牌,我就滿足了。
但在別人的經營績效考核角度上,可能不怎麼樣。
這點我也非常認同,因為原本也以為可以在那個領域裡,
不斷的深根茁壯....但我們也不可否認的:
不只那個技術產業市場在變,就連相關技術走向也在變。
沒有足夠的資源可以供你順著產業市場發展深根時,
那已經不是你關起門來,蹲著深耕就可以有所成就了啊。
興趣,當然還是興趣啊,但就不要有那麼大的壓力啊。
或是真的要換個腦袋或角度來思考了啊。但肯定就不是
原來那一種宅男工程師的那個德性的搞一輩子吧。😁😂😂
套著這兩天那個政大商學院副院長買馬莎拉蒂的新聞:
獨家/靠0050買瑪莎拉蒂! 揭密財金教授「躺著賺」心法
https://fnc.ebc.net.tw/fncnews/headline/177592
剛好驗證我一直強調的概念:
想技術與營收兼顧,很好啊~你就去學校當老師啊。
有個穩定的固定收入,又可以讓你學以致用,
只不過:背後也有很多不為人知的鳥事啊:
李清志/提前退休的理由
https://udn.com/news/story/7340/8273071
"雖然熱愛教學,但我也是個喜愛自由、討厭體制的人,
無法忍受現在教育單位沒有意義的開會、填表格、評鑑、
積點數等等行政作業,我認為這些事其實是在浪費我的生命..."
是啊,~只要是單位組織團隊,就得要稽核考察管理啊。
要不然,別人也會說三道四的啊。
我也只想好好當個可以整天搞技術的工程師啊,
我也不想接部門主管,有太多的行政Paper Work 的雜事啊。
這些事情都不是大家表面所想的那麼單純簡單的啦。
至於手機APP,應該換個說法啦:行動通訊平台,
因為還要包括車用平台等,我當然也知道未來會比
PC 個人電腦有前途未來啊,那就更不用說:
背後那個龐大的雲端資料運算處理中心啊。
大家都懂,不管是搞技術的、或市場分析投資理財
等專家。只是我們手上有多少資源(時間與金錢),
可以讓我們去參與而已。大家就努力加油吧。
我想我知道問題在那裏了。我之所以什麼都評估,每次評估好都寫成數位筆記,以方便後面尋找再整理,這是另一個退休企業家要我做的。我可能不知不覺開始變成習慣。我會去請教他一些問題,大部分都只得到方向。然後他教我什麼事都要懂一點,因為企業上百人上千人什麼狀況都可能發生。我本來覺得這樣不就什麼都學,是不可能學完的。但幾年下來我發現方向錯了。學的不是事情本身,而是事情的模型,了解事情前因後果,類似的事很情就可以上手。這是他管理企業的方式,我照他的方法做,確實是有用的。
刪除不錯。
刪除我知道很多工程師的性格都有點自戀的只相信自己。
就算有人願意分享一些經驗或見解時,
工程師有時都會覺得人家是意有所指地指責他的缺失。
聽不進耳朵的,可能就是對你的忠言。
過度的相信自己的信仰:唯有擁有技術就是崇高的理念。
本來有多事情,都不是絕對的對與錯,
也不可能可以給你一個明確的方向與方法。
誠如你所說的:就是一個方向或是一個模型與邏輯推理原則。
如果年輕時,無法做到廣納建言,調整思考與做事的原則。
越老時,就越難改進與修正...就越會相信自我。
惡性循環的結果就是我所說:
工程師一生最後窮到只剩下一些自認一身功夫在身而已。
至於有沒有用?就你以前提過的那位8051 組合語言大師一樣。
躺在安寧病房裡,還是沒有人看得懂他的程式。
也沒有人有興趣想去了解吧。
這是我們身為工程師們所需要不斷的反省與修正的。
活出自己有尊嚴又自在的工程師人生。
https://tw.news.yahoo.com/uscaseai-011618855.html
回覆刪除這件事在AI圍棋比勝人類時我就查過了。當時就確認沒有版權。所以我就提出一個極端案例,萬一有人用AI仿某產品的操作,經過訓練生成出來的產品又拿去賣,是不會侵權的。然後現在AI可以產生程式,所以我設定的時機也就是到了。
我寫太少了。因為這個現象,AI公司也知道,也就是原先很多專利卡住的都有機會利用AI繞過去,變成先佔先贏。產品到時又重新洗牌,只有AI平台公司是贏家。
刪除今年諾貝爾物理獎公布了。
刪除得獎的內容就是跟AI 有關。
"AI教父獲諾貝爾物理獎,這會不會「不夠物理」?"
https://www.techbang.com/posts/118799-is-it-reasonable-that-the-godfather-of-ai-won-the-nobel-prize
這個趨勢是無庸疑置的,他也會深入到每個生活的應用領域,
會改變我們研究創造或生產管理等方面(包括你所說的智權)。
為什麼各個領域的學者、公司企業要不斷的研究評估。
當然大家也都看到了啊。
不是我們不願意去參與或學習,就你所說:你看得到,
公司企業也看得到啊。AI 公司更是快馬加鞭啊。
我們就只能趕快的調整自己方法與思考模式。
從中間去找出一塊可以利用AI 資源與我們本身經驗的
資料庫,來為自己創造未來的機會。
其實網路上已經有很多AI 資料庫的平台了,
包含那些開源平台也都是,我們現在也已經開始無形中
使用與貢獻充實這些資料庫了。
也已經由不得你的願不願意決定與否了。
就小弟所知,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直接套三菱的軟體
基本上,要用哪一種語言發展公司產品,坦白說,
刪除老闆是不會管你們研發單位的,程式寫一寫有問題,
效率不好?
那就請你們自行免費加班、也不要額外開銷把問題解了吧。
滿街能招來的工程師絕大部分都會C/C++,
你跟老闆說:我們要花時間學習與轉換以外的程式語言。
你跟我說:台灣有幾個老闆可以忍受你這種藉口、說法?
Microsoft、Amazon ? 人家大公司有資源,而且老外
也懂得尊重寫程式的人員,所以你對Rust 的見解我同意,
但如果在台灣哪家公司可以實現這件事,你再跟我分享一下。
我肯定要好好的膜拜一下這公司的老闆開明作風。😁😂😂
至於 PLC 的工程與市場問題,這就是回到工程師的心態了。
真的過度膨脹自己的能力與想法了。
別的不說:就簡單的把自己搞完的技術,有系統地對公司
內部進行教育訓練時,道理是一樣的:老闆的看法跟你工程師
的看法是否一致?
往往會有這些想法的人,都是那些小公司,老闆就是搞技術的人,
就整天異想天開的覺得:自己的技術不得了了,肯定可以掀起
市場革命的,我會一統天下這些傳統企業的這些老產品....
就跟電動機車的G 公司老闆一樣,只要我一出江湖,這些
做油車的傳統機車廠肯定會吃鱉,然後每一家就準備倒閉收攤。
結果:最後就是人家還是活得好好的,是你自己先掛了。😁😂😂
那些山寨的東西,不是不能做,也不是沒有市場,
但人家大公司,大企業投資弄工廠,搞生產線,不會缺
那幾塊錢的啦。(況且現在那些PLC 大廠成熟的東西,也
貴不到哪裡去啊。) 搞山寨的產品市場,也不光只是技術
而已啦。還是同樣存在市場策略問題。
搞產品技術終究有一天你可能會追上大廠,但然後呢?
就靠嘴巴整天吹就好?你總得還是要透過業務市場去推啊。
我們就看你怎麼先說服你的市場業務人員?
你就不用再出資源?公司的市場業務人員不用管銷費用?
你想賺個5~10% 就好。(你覺得很好賺~) 但人家市場業務
通路也要抓個5~10% 利潤....(還沒算到工廠生產備料成本)
最後,東加西加...加個 30~40%,你還能跟大廠的報價比嗎?
是不是最後又是笑話一則?怎樣?你要罵業務市場通路人員
無良心?你最聰明、最厲害?老闆是笨蛋,不會聽你的?
人年紀大了,就不要老是那麼天真了啦。
市場,世界會長成這個樣子不是沒有道理的啦。
GodSpeed 你同不同意我的看法呢?😁😂😂
小弟就是靠C++維生的,C++有分C++98,C++11,C++17,C++20等n個版本,來面試的人考筆試,我還得在考卷上特別註明是哪個版本,就算如此還是有人寫錯...基本上firmware還是C,C++太混亂了
刪除C/C++之所以還能在路上找到一堆,那是因為歷史包袱太大了,非得找人來維護,但對於年輕人(不包括我)來說,如果讓他賭Rust賭對了那就不得了了,事實上104上還是找得到近數十間公司在找會Rust的人,尤其對於新創來說沒有包袱,更是可以大膽採用
至於PLC,本來沒有暴利可圖,工控要導入,驗證一樣產品,那個時間之長,量又少,我是不知道哪個人想不開會想去玩,再來講一個重點,寫PLC的人大多是傳產,薪水很低,而且上游插旗都插滿了,不講三菱西門子,國內永宏,台達電,豐煒這三間就插滿旗子了,這三間起碼在市場蹲20年了,而且要便宜,這三間也有超便宜的機種,會想弄Arduino PLC的人我覺得這人應該不是巷子內的才會在那座夢吧
你說對了:有很多人事物都是有包袱的。
刪除搞軟體寫程式也是,公司若一開始就用C/C++,就不容易改。
你所說的那些使用Rust 的公司,難道也沒有嗎?
所以啦,我現在看事情就比較平常心,真的也不會說:
哪個程式語言比較好?誰的技術有多好?哪家公司就比較好?
反正啦,只要人家可以順順利利、平平安安的上班賺錢就好。
一家人可以幸福美滿快樂就好。
另外關於招人考寫程式這件事,我前一陣子不知道在哪篇
文章中,看到好像一位國際知名的程式軟體大師,就非常反對
招募用考程式這種方式,如果是這樣子的話:
我這輩子應該就沒機會找到寫程式的工作了,就算自學個
幾年,我也不知道我自己可不可以過得了那一關。
或許是不同的公司有不同的看法吧。至少我在園區幾家
大公司就真的比較少聽到,我想像聯發科要找台清交的
畢業生,應該只是看看學歷或在校成績,應該不會還要
搞一套入職考C/C++。在這些公司裡,你寫程式程度不好,
也趕不上研發團隊的進度時,應該也不用很久就會陣亡了吧。
如果:你真的很努力地花時間可以趕上研發團隊的進度,
我想那個積極的態度是比你C/C++程度好壞還重要吧。
可能就你說的:小公司賭不起人員淘汰率吧。
所以我有時候會覺得:有機會去人家大公司待著晃晃看看,
也是一種不錯的經驗體會的。
關於類似PLC 的這種成熟產品市場,都是可以供大家一個
從技術以外的觀點來思考一些:產品研發到底是要從技術
角度呢?還是從市場行銷或使用者角度?
市面上有很多這種產品東西。像我做的數位CDI,滿街都是了。
有各式各樣,有簡單便宜的難以想像,但是我還是有訂單。
餓不死,當然也賺不了大錢啊。你說:我還會一直投入資源,
或拿這種技術出來吹嗎?那如果還有別人想出來做類似的產品。
喔~很好啊~我也不會唱衰你,你就慢慢的自己孵吧。
另外,我最近才知道:除了知名的 Raspberry Pi 外,
市面上還有一個 Banana Pi,他是由我以前公司的一位同事
在鴻海時做的,他後來把這個東西交給大陸人之後,就離開了。
他私底下說:這個東西還是真的比不上Raspberry Pi 的啦。
主要還是在於市場主流資源的啦。其實道理也都是一樣的。
這些都不是你工程師個人或是侷限在一個資源有限的小團隊裡,
長期堅持或努力就可以了。
初期努力,那是一種幻想與夢想,從學習的角度來說:很好。
但五年,十年,二十年...那你到底是在做甚麼?
時代環境會一直改變,你原本覺得有技術市場機會的,
是啊,可能真的有市場機會的,有資源別的公司與團隊,
隨時都可以直接超越你,更可以狠狠的把你甩到很遠之處。
屆時就你所說的:就只能困在一個狹小的小巷內,
在社群媒體群組裡,討討按讚數,抱團取暖而已。
有些人事物,如果我們可以跳脫原來的框架想想,
或許都是一些很好正面的人生導師啊。
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
現在因應高速發展的資訊軟體功能,未來還有甚麼軟體架構,
刪除都很難說了,那你說:學甚麼比較有未來?
只要有人願意付薪水給你的就可以了,而且未來還可以不斷
的加薪比較重要,要不然就跟以前學組合語言一樣:
一開始也有人願意付薪水給你,但後來就慢慢的沒啥加薪機會了。
未來萬一大家都用AI 幫忙寫程式了,學甚麼語言就沒那麼重要了。
MTK 或其他一線大公司所找的台清交一流畢業生來上班,
用甚麼軟體平台,對他們來說都不是很難的啦,
沒一個月內上手的,大概就準備要丟履歷去找別的工作了。
那些頂尖的學生,在學校念書考試就像學霸一般的,
你認為念書學個語言程式碼,對他們來說:真的很難嗎?
我是老闆,根本不用擔心這種事啊。
我說過了,就只有我們這種苦讀出身的工程師,挑選可以
安身立命的程式語言技巧或謀生技能,就得戰戰兢兢的,
因為一投入下去的代價很高,賭不起這種風險。
對他們這些公司的領導來說:要說服我的不是甚麼程式語言?
而是我老闆付了你們這些人高薪之後,你們要跟我說:
我的產品如何在世界激烈的競爭市場中,如何勝出吧?
看看人家現在 tsmc/Nvidia/AMD/Intel/Qalcomm/MTK 或
Google 這些一流國際公司殘酷的競爭態勢時,
就知道甚麼是未來?
至於我們這些沒機會站上這些舞台的工程們來說:
就是要務實一點:誰付我薪水,未來還有機會加薪,
最好還可以幫我支付勞健保到退休...我就阿彌陀佛了,
感謝上帝囉。
"這些東西不要再學了,這是我們那個年代的宿命", 工作一段時間之後的工程師才會懂得這句話的重量. 尤其是IT跟EE產業的.
回覆刪除https://www.tiobe.com/tiobe-index/
刪除組合語言仍在前20名上面,為何不要再學?
工具本來就有限定,只是IT換得比較快,因為進展快。重點是趨勢在那裏,而不在於工具本身。如果只是追流行,自然不知道工具學了要怎用,只是糊口。
IT的最基本就是碼,組合語言就是最基本機械做事的方法,原理要學,但不可鎖定在單一目標上。
對不起囉。
刪除如果我還在MCU 設計公司上班的話,那肯定還是會玩組合語言的。
但現在要我去用組合語言為主來開發系統產品,
除非真的有老闆或金主付我薪水強烈要求我用組合語言,
我也不反對啦。我這種年紀考慮的就真的只有餬口而已。
今天中午剛好跟我以前一位老同事吃飯,
就是我上回提到後來去了鴻海搞 Banana Pi 平台的那位。
他離開鴻海之後,有個因緣際會去搞了一年多Python 。
像我們這種年紀,學得有點辛苦,結果今年上班的公司收了,
領了資遣費,也領了幾個月的失業救濟金...
幸好最近有接到工作通知了....做甚麼?用甚麼程式語言?
不重要了...還是替他感到高興的啦。
這個組合語言,有99%討論的是WebAssemble。是用來加速瀏覽器去執行Game的方法。也就是瀏覽器內建一個byte code直譯器就直接執行使用者的檔案。並不是在MCU上執行。但它有一個副專案,就是再轉成ARM的機器碼。因為windows on ARM開始變得流行,本來從VM(虛擬機)上執行也有可能轉成實體CPU執行。它算是IOT的一部分。我認為若是edge IOT未來是可以利用WebAssemble載入去執行使用者程式。
刪除是...是...是...
刪除如果架上組合語言就是為了某些系統使用需求,
我相信都是可以接受到,就像我以前在MCU 設計公司上班,
為了確認MCU 每條機械指令都可以準確執行無誤,
當然就得整天寫組合語言啊,但你要把MCU 賣給客人市場之後,
你還要客人用你的MCU 還要這麼搞?那不就玩死客人,
也玩死自己嗎。所以終究還是得看產品市場的目的吧。
程式語言都是隨著市場需求不斷的修正與演進的。
當然也包括著相關組譯器與開發平台。
這些都無非就是為了輕易推廣自家產品平台。
是啊,高階語言效能是比較低啊,但人家現在硬體效能
與周邊資源一直提升,當然就是為了彌補這些程式語言的
缺失與不足之處。
NVidia 為了推他們的顯示圖卡硬體架構應用在AI 系統上,
人家也不得不重新開發一套 CUDA 平台。
所以說啦:甚麼程式語言好用?流行?
或實際一點說:學甚麼程式語言比較有前途(錢途)?
就看每個仁自己的判斷與認知。
也祝各位可以在每個人的工作生涯裡,都可以如魚得水的
幸福快樂的寫程式,一套軟體語言技能可以永保安康的
終身受用啊。
我查了一下 Nvidia 的CUDA 平台的評價:
刪除NVIDIA 軟體戰略全面解析:建構未來幾年內難以撼動、既寬且深的護城河
https://blog.finsight.investments/portfolio/nvidia-nvda-leading-software-ai-platform-continuous-innovation/
這只有在國外軟體盛行的環境哩,才有辦法成形的。
我們在國內就只能依附在大廠思維底下當個追隨者而已。
回頭看STM32它已經平台化成功,對岸仿硬體,但利用其軟體工具,且不只一家。CUDA推出前5年,幾乎沒人在用,因為要改寫,好在它是C,我也從CPU C改成CUDA過。STM32知道平台化一定在軟體,第一件事就是推出HAL library然後自打自家的std library。HAL有了,再來買下IDE公司,推出STM32CubeIDE這個平台核心工具,再配合STM32CubeMX這個雲端平台界面。三者就是一整個平台化關鍵。一開始bug很多,多到STM32CubeIDE根本被認為是爛工具(和keil比),改到現在做ARM MCU的公司都不得不做類似的軟體工具,連硬體都想要去相容。這個是相容IP下單一廠商平台化成功的案例。
刪除接回主題。廣度是可以利用其他行業的手法,在成熟的科技背景下引入新管理方法的路徑。深度就是要調整本業去符合新手法的方法。
刪除不管是 STM32 的開發工具平台化,或是討論技術廣度來說:
刪除其實都在說明一件事:誠如你所說的平台經濟概念。
這都不只是影響整個未來世界潮流,
也當然會改變我們在技術開發的一些觀念上。
AI︱發展神速超乎想像:AI雲端資金流入加速,今年預估可達790億美元!
https://uanalyze.com.tw/articles/212107391
投資就是代表著科技未來,更不用這些檯面上科技技術領域裡
數一數二的大公司,當然人家也不是笨蛋。
說真的:這個時間點,如果讓我再年輕個二、三十歲的話,
我當然就不會再花太多心思在甚麼單晶片韌體、或引擎、馬達
控制技術上面了。因為這些都已經是成熟科技技術了。
藉由如何善用這些平台先進技術來幫我們引進新的技術管理方法。
人家大公司 像stm32 這種有資金(去購併)、有豐沛的資源(結合
全球各地科技技術人員投入),把他們的開發平台完善到各個應用
領域裡,都可以輕易簡單上手了。
人家是有錢可以去搞平台,我們就另一種人:真的要懂得如何
利用平台了。如果沒有認清這一點:學甚麼技術?做甚麼產品
開發或是講甚麼理想、夢想等,其實還是不夠務實確切的啦。
這是我自己的感想啦。
今天看到的日本冷氣大廠日立的故事:
回覆刪除當代日本三大企業,賣家電賣到快破產?!日立如何從存亡邊緣浴火重生?
https://www.youtube.com/watch?v=9QNb4qnOn1Y
這麼大的企業,尤其在冷氣空調大廠技術成就,
不管是馬達或相關技術開發。
肯定就是業界的一等一的優等生。
但這個故事就是告訴我們:這些技術到了一個
頂峰之後,面臨的就是現實的市場競爭。
單一技術頂峰是幫不了企業創造持續獲利的。
唯有更積極的整合系統,搭配時代應用需求,
引入更高端與市場應用端的技術,才能再創佳績。
這也是明確的告訴我們:不是該做甚麼技術或甚麼事。
而真的明確的告訴我們:在面對競爭與資源有效應用時,
"是甚麼事,就不要去做了!"
(應該更專注本身的優勢,趕快轉型去迎接下一個機會!)