在平時(shí)編寫STM32單片機(jī)代碼時(shí),我們經(jīng)常會遇到某一個(gè)函數(shù)或某一個(gè)變量需要反復(fù)調(diào)試的情況,而常用的方法只能是在源碼修改并下載至單片機(jī)調(diào)試。反復(fù)這樣不僅麻煩,而且反復(fù)燒寫單片機(jī)對其FLASH也有影響,因此就考慮編寫一款小工具,可以實(shí)現(xiàn):
?1)通過串口控制單片機(jī)執(zhí)行我們期望的函數(shù),同時(shí)函數(shù)參數(shù)最大支持5個(gè),其參數(shù)類型支持char、short、int、float及其無符號類型和相應(yīng)的指針,不支持long及double。
?2)對于含有對字符串及數(shù)組操作的函數(shù),需要通過數(shù)組傳值后,在調(diào)用函數(shù)時(shí)寫入該變量地址才能實(shí)現(xiàn)對這些變量的操作。支持函數(shù)返回值得顯示。
?3)支持對全局變量進(jìn)行任意的修改。
?4)支持十進(jìn)制與十六進(jìn)制切換.
?5)通訊超時(shí)自動(dòng)重傳或關(guān)閉串口。
?建議配合KEIL一起使用,效果更好。
?本軟件使用C#編寫,運(yùn)行環(huán)境為NET 4.5。
?先讓大家看看效果,感興趣的話可以繼續(xù)往下看:
?1.上位機(jī)調(diào)試設(shè)置
? ?
2.函數(shù)調(diào)用
? ?
3.全局變量的寫入
? ?
4.通訊超時(shí)處理
? ?
二、上位機(jī)的處理 ?
2.1 原理 ?在使用keil編譯STM32后,我們會在.hex文件的同一個(gè)文件夾中發(fā)現(xiàn)一個(gè).map文件。這個(gè).map文件包含了源碼中函數(shù)與全局變量的地址、大小、優(yōu)化等信息。這里貼一個(gè)簡化的.map文件給大家看一下: ?
?Component: ARM Compiler 5.06 update 6 (build 750) Tool: armlink [4d35ed]
==============================================================================
Section Cross References
? ? startup_stm32f103xe.o(STACK) refers (Special) to heapauxi.o(.text) for __use_two_region_memory
? ? startup_stm32f103xe.o(HEAP) refers (Special) to heapauxi.o(.text) for __use_two_region_memory
? ? startup_stm32f103xe.o(RESET) refers (Special) to heapauxi.o(.text) for __use_two_region_memory
? ? startup_stm32f103xe.o(RESET) refers to startup_stm32f103xe.o(STACK) for __initial_sp
==============================================================================
Removing Unused input sections from the image.
? ? Removing main.o(.rev16_text), (4 bytes).
? ? Removing main.o(.revsh_text), (4 bytes).
? ? Removing main.o(.rrx_text), (6 bytes).
? ? Removing gpio.o(.rev16_text), (4 bytes).
? ? Removing gpio.o(.revsh_text), (4 bytes).
384 unused section(s) (total 34104 bytes) removed from the image.
==============================================================================
Image Symbol Table
? ? Local Symbols
? ? Symbol Name? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?Value? ???Ov Type? ?? ???Size??Object(Section)
? ? ../Core/Src/gpio.c? ?? ?? ?? ?? ?? ?? ???0x00000000? ?Number? ?? ?? ?0??gpio.o ABSOLUTE
? ? ../Core/Src/main.c? ?? ?? ?? ?? ?? ?? ???0x00000000? ?Number? ?? ?? ?0??main.o ABSOLUTE
? ? ../Core/Src/stm32f1xx_hal_msp.c? ?? ?? ? 0x00000000? ?Number? ?? ?? ?0??stm32f1xx_hal_msp.o ABSOLUTE
? ? ../Core/Src/stm32f1xx_it.c? ?? ?? ?? ?? ?0x00000000? ?Number? ?? ?? ?0??stm32f1xx_it.o ABSOLUTE
? ? ../Core/Src/system_stm32f1xx.c? ?? ?? ???0x00000000? ?Number? ?? ?? ?0??system_stm32f1xx.o ABSOLUTE
? ? ../Core/Src/tim.c? ?? ?? ?? ?? ?? ?? ?? ?0x00000000? ?Number? ?? ?? ?0??tim.o ABSOLUTE
? ? ../Core/Src/usart.c? ?? ?? ?? ?? ?? ?? ? 0x00000000? ?Number? ?? ?? ?0??usart.o ABSOLUTE
? ? ../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal.c 0x00000000? ?Number? ?? ?? ?0??stm32f1xx_hal.o ABSOLUTE
? ? ../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_cortex.c 0x00000000? ?Number? ?? ?? ?0??stm32f1xx_hal_cortex.o ABSOLUTE
? ? ../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_dma.c 0x00000000? ?Number? ?? ?? ?0??stm32f1xx_hal_dma.o ABSOLUTE
? ? ../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_exti.c 0x00000000? ?Number? ?? ?? ?0??stm32f1xx_hal_exti.o ABSOLUTE
? ? Global Symbols
? ? Symbol Name? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?Value? ???Ov Type? ?? ???Size??Object(Section)
? ? BuildAttributes$THM_ISAv4$P$D$K$B$S$PE$A:L22UL41UL21$X:L11$S22US41US21$IEEE1$IW$USESV6$~STKCKD$USESV7$~SHL$OSPACE$ROPI$EBA8$UX$STANDARDLIB$REQ8$PRES8$EABIv2 0x00000000? ?Number? ?? ?? ?0??anon$obj.o ABSOLUTE
? ? __ARM_use_no_argv? ?? ?? ?? ?? ?? ?? ?? ?0x00000000? ?Number? ?? ?? ?0??main.o ABSOLUTE
? ? __ARM_exceptions_init? ?? ?? ?? ?? ?? ?? ?- Undefined Weak Reference
? ? __alloca_initialize? ?? ?? ?? ?? ?? ?? ???- Undefined Weak Reference
? ? __arm_preinit_? ?? ?? ?? ?? ?? ?? ?? ?? ? - Undefined Weak Reference
? ? __cpp_initialize__aeabi_? ?? ?? ?? ?? ?? ?- Undefined Weak Reference
? ? _terminate_alloc? ?? ?? ?? ?? ?? ?? ?? ???- Undefined Weak Reference
? ? _terminate_user_alloc? ?? ?? ?? ?? ?? ?? ?- Undefined Weak Reference
? ? _terminateio? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?- Undefined Weak Reference
? ? __Vectors_Size? ?? ?? ?? ?? ?? ?? ?? ?? ?0x00000130? ?Number? ?? ?? ?0??startup_stm32f103xe.o ABSOLUTE
? ? __Vectors? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???0x08000000? ?Data? ?? ?? ???4??startup_stm32f103xe.o(RESET)
? ? __Vectors_End? ?? ?? ?? ?? ?? ?? ?? ?? ? 0x08000130? ?Data? ?? ?? ???0??startup_stm32f103xe.o(RESET)
? ? __main? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???0x08000131? ?Thumb Code? ???8??__main.o(!!!main)
? ? in? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?0x2000001c? ?Data? ?? ?? ???4??main.o(.data)
? ? uin? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???0x20000020? ?Data? ?? ?? ???4??main.o(.data)
? ? uwTick? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???0x20000024? ?Data? ?? ?? ???4??stm32f1xx_hal.o(.data)
? ? uwTickPrio? ?? ?? ?? ?? ?? ?? ?? ?? ?? ? 0x20000028? ?Data? ?? ?? ???4??stm32f1xx_hal.o(.data)
? ? uwTickFreq? ?? ?? ?? ?? ?? ?? ?? ?? ?? ? 0x2000002c? ?Data? ?? ?? ???1??stm32f1xx_hal.o(.data)
==============================================================================
Memory Map of the image
??Image Entry point : 0x08000131
??Load Region LR_IROM1 (Base: 0x08000000, Size: 0x00002de8, Max: 0x00080000, ABSOLUTE, COMPRESSED[0x00002da8])
? ? Execution Region ER_IROM1 (Exec base: 0x08000000, Load base: 0x08000000, Size: 0x00002b94, Max: 0x00080000, ABSOLUTE)
? ? Exec Addr? ? Load Addr? ? Size? ?? ?? ?Type? ?Attr? ?? ?Idx? ? E Section Name? ?? ???Object
? ? 0x08000000? ?0x08000000? ?0x00000130? ?Data? ?RO? ?? ?? ?? ?3? ? RESET? ?? ?? ?? ?? ?startup_stm32f103xe.o
? ? 0x08000130? ?0x08000130? ?0x00000008? ?Code? ?RO? ?? ?? ?2955??* !!!main? ?? ?? ?? ? c_w.l(__main.o)
? ? 0x08000138? ?0x08000138? ?0x00000034? ?Code? ?RO? ?? ?? ?3143? ? !!!scatter? ?? ?? ? c_w.l(__scatter.o)
? ? 0x0800016c? ?0x0800016c? ?0x0000003a? ?Code? ?RO? ?? ?? ?3141? ? !!dczerorl? ?? ?? ? c_w.l(__dczerorl.o)
? ? 0x080001a6? ?0x080001a6? ?0x00000002? ?PAD
? ? 0x080001a8? ?0x080001a8? ?0x0000001c? ?Code? ?RO? ?? ?? ?3145? ? !!handler_zi? ?? ???c_w.l(__scatter_zi.o)
? ? Execution Region RW_IRAM1 (Exec base: 0x20000000, Load base: 0x08002b94, Size: 0x00008bb0, Max: 0x00010000, ABSOLUTE, COMPRESSED[0x00000214])
? ? Exec Addr? ? Load Addr? ? Size? ?? ?? ?Type? ?Attr? ?? ?Idx? ? E Section Name? ?? ???Object
? ? 0x20000000? ?COMPRESSED? ?0x00000010? ?Data? ?RW? ?? ?? ???18? ? .data? ?? ?? ?? ?? ?test.o
? ? 0x20000010? ?COMPRESSED? ?0x00000014? ?Data? ?RW? ?? ?? ???78? ? .data? ?? ?? ?? ?? ?main.o
? ? 0x20000024? ?COMPRESSED? ?0x00000009? ?Data? ?RW? ?? ?? ?1481? ? .data? ?? ?? ?? ?? ?stm32f1xx_hal.o
? ? 0x2000002d? ?COMPRESSED? ?0x00000003? ?PAD
? ? 0x20000030? ?COMPRESSED? ?0x00000004? ?Data? ?RW? ?? ?? ?2832? ? .data? ?? ?? ?? ?? ?system_stm32f1xx.o
? ? 0x20000034? ?COMPRESSED? ?0x00000004? ?PAD
? ? 0x20000038? ?COMPRESSED? ?0x0000021c? ?Data? ?RW? ?? ?? ?2910? ? .data? ?? ?? ?? ?? ?debug_revice.o
==============================================================================
Image component sizes
? ?? ?Code (inc. data)? ?RO Data? ? RW Data? ? ZI Data? ?? ?Debug? ?Object Name
? ?? ? 172? ?? ?? ? 6? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?? ? 3002? ?debug_function.o
? ?? ? 580? ?? ?? ?98? ?? ?? ? 0? ?? ???540? ?? ? 2104? ?? ? 3763? ?debug_revice.o
? ?? ???36? ?? ?? ? 4? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?? ???767? ?gpio.o
? ?? ? 288? ?? ?? ?24? ?? ?? ? 0? ?? ?? ?20? ?? ?? ?50? ???486558? ?main.o
? ?? ???64? ?? ?? ?26? ?? ???304? ?? ?? ? 0? ?? ?32768? ?? ???820? ?startup_stm32f103xe.o
? ?? ? 152? ?? ?? ?32? ?? ?? ? 0? ?? ?? ? 9? ?? ?? ? 0? ?? ? 5977? ?stm32f1xx_hal.o
? ?? ? 304? ?? ?? ?22? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?? ?29503? ?stm32f1xx_hal_cortex.o
? ?? ? 510? ?? ?? ?10? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?? ? 1927? ?stm32f1xx_hal_dma.o
? ?? ? 832? ?? ?? ?40? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?? ? 2092? ?stm32f1xx_hal_gpio.o
? ?? ???84? ?? ?? ? 8? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?? ???918? ?stm32f1xx_hal_msp.o
? ?? ?1784? ?? ???110? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?? ? 6112? ?stm32f1xx_hal_rcc.o
? ?? ?1260? ?? ?? ?44? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?? ? 9974? ?stm32f1xx_hal_tim.o
? ?? ? 160? ?? ?? ?22? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?? ? 2453? ?stm32f1xx_hal_tim_ex.o
? ?? ?1844? ?? ?? ?10? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?? ?11460? ?stm32f1xx_hal_uart.o
? ?? ???66? ?? ?? ?12? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?? ? 4980? ?stm32f1xx_it.o
? ?? ?? ?2? ?? ?? ? 0? ?? ?? ?24? ?? ?? ? 4? ?? ?? ? 0? ?? ? 1155? ?system_stm32f1xx.o
? ?? ? 134? ?? ?? ?10? ?? ?? ? 0? ?? ?? ?16? ?? ?? ? 0? ?? ? 6385? ?test.o
? ?? ? 192? ?? ?? ?18? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ?72? ?? ? 1702? ?tim.o
? ?? ? 220? ?? ?? ?26? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ?68? ?? ? 1778? ?usart.o
? ? ----------------------------------------------------------------------
? ?? ?8702? ?? ???522? ?? ???362? ?? ???596? ?? ?35068? ???581326? ?Object Totals
? ?? ?? ?0? ?? ?? ? 0? ?? ?? ?32? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?(incl. Generated)
? ?? ???18? ?? ?? ? 0? ?? ?? ? 2? ?? ?? ? 7? ?? ?? ? 6? ?? ?? ? 0? ?(incl. Padding)
? ? ----------------------------------------------------------------------
? ?? ?Code (inc. data)? ?RO Data? ? RW Data? ? ZI Data? ?? ?Debug? ?Library Member Name
? ?? ???58? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?__dczerorl.o
? ?? ?? ?8? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ?68? ?__main.o
? ?? ?? ?0? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?__rtentry.o
? ?? ???12? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?__rtentry2.o
? ?? ?? ?6? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?__rtentry4.o
? ?? ???52? ?? ?? ? 8? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?__scatter.o
? ?? ???28? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?__scatter_zi.o
? ?? ???18? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ?80? ?exit.o
? ?? ?? ?6? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?? ???152? ?heapauxi.o
? ?? ?? ?0? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?indicate_semi.o
? ?? ?? ?2? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?libinit.o
? ?? ?? ?2? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?libinit2.o
? ?? ?? ?2? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?libshutdown.o
? ?? ?? ?2? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?libshutdown2.o
? ?? ?? ?8? ?? ?? ? 4? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ?96? ?? ?? ?68? ?libspace.o
? ?? ???78? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ?80? ?rt_memclr_w.o
? ?? ?? ?2? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?rtexit.o
? ?? ???10? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?rtexit2.o
? ?? ???12? ?? ?? ? 4? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ?68? ?sys_exit.o
? ?? ???74? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ?80? ?sys_stackheap_outer.o
? ?? ?? ?2? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ?68? ?use_no_semi.o
? ?? ? 804? ?? ?? ?16? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?? ???272? ?daddsub_clz.o
? ?? ???90? ?? ?? ? 4? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ?92? ?dfixu.o
? ?? ? 156? ?? ?? ? 4? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ?92? ?dnaninf.o
? ?? ???12? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ?68? ?dretinf.o
? ?? ? 430? ?? ?? ? 8? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?? ???168? ?faddsub_clz.o
? ?? ???62? ?? ?? ? 4? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ?84? ?ffixu.o
? ?? ? 140? ?? ?? ? 4? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ?84? ?fnaninf.o
? ?? ???10? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ?68? ?fretinf.o
? ?? ?? ?0? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?usenofp.o
? ? ----------------------------------------------------------------------
? ?? ?2092? ?? ?? ?56? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ?96? ?? ? 1592? ?Library Totals
? ?? ?? ?6? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?(incl. Padding)
? ? ----------------------------------------------------------------------
? ?? ?Code (inc. data)? ?RO Data? ? RW Data? ? ZI Data? ?? ?Debug? ?Library Name
? ?? ? 382? ?? ?? ?16? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ?96? ?? ???664? ?c_w.l
? ?? ?1704? ?? ?? ?40? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ? 0? ?? ???928? ?fz_ws.l
? ? ----------------------------------------------------------------------
? ?? ?2092? ?? ?? ?56? ?? ?? ? 0? ?? ?? ? 0? ?? ?? ?96? ?? ? 1592? ?Library Totals
? ? ----------------------------------------------------------------------
==============================================================================
? ?? ?Code (inc. data)? ?RO Data? ? RW Data? ? ZI Data? ?? ?Debug? ?
? ???10794? ?? ???578? ?? ???362? ?? ???596? ?? ?35164? ???577922? ?Grand Totals
? ???10794? ?? ???578? ?? ???362? ?? ???532? ?? ?35164? ???577922? ?ELF Image Totals (compressed)
? ???10794? ?? ???578? ?? ???362? ?? ???532? ?? ?? ? 0? ?? ?? ? 0? ?ROM Totals
==============================================================================
? ? Total RO??Size (Code + RO Data)? ?? ?? ?? ?? ? 11156 (??10.89kB)
? ? Total RW??Size (RW Data + ZI Data)? ?? ?? ?? ? 35760 (??34.92kB)
? ? Total ROM Size (Code + RO Data + RW Data)? ?? ?11688 (??11.41kB)
仔細(xì)觀察可以發(fā)現(xiàn).map文件主要由以下幾個(gè)部分組成:
?
Component: ARM Compiler 5.06 update 6 (build 750) Tool: armlink [4d35ed]
==============================================================================
Section Cross References
==============================================================================
Removing Unused input sections from the image.
==============================================================================
Image Symbol Table
? ? Local Symbols
? ? Symbol Name? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?Value? ???Ov Type? ?? ???Size??Object(Section)
? ?? ???
? ?? ???
? ? Global Symbols
? ? Symbol Name? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?Value? ???Ov Type? ?? ???Size??Object(Section)
? ?
==============================================================================
Memory Map of the image
==============================================================================
Image component sizes
==============================================================================
? ?? ?Code (inc. data)? ?RO Data? ? RW Data? ? ZI Data? ?? ?Debug? ?
==============================================================================
? ? Total RO??Size (Code + RO Data)? ?? ?? ?? ?? ?
? ? Total RW??Size (RW Data + ZI Data)? ?? ?? ?? ?
????Total?ROM?Size?(Code?+?RO?Data?+?RW?Data)??????
?
而我們最關(guān)注的信息如函數(shù)和全局變量的地址與大小都在.map文件中的Image Symbol Table->Global Symbols。知道了這些地址,我們只需將其感興趣的函數(shù)與變量地址發(fā)送給單片機(jī),單片機(jī)通過指針就可以執(zhí)行相應(yīng)的函數(shù)了。整個(gè)上位機(jī)正是基于這個(gè)原理而編寫的。具體流程如下圖所示:
?
?
2.2 class Get_Map_Address_And_Size_Table的實(shí)現(xiàn)——————.map中函數(shù)和全局變量的地址與大小等信息提取
?
函數(shù)和全局變量的地址與大小都在.map文件中的Image Symbol Table->Global Symbols,由Symbol Name、Value、Ov Type、Size、Object(Section)組成,所以先定義一個(gè)public struct Symbol來包含上述信息:
?
public struct Symbol
{
? ?public String Symbol_Name;
? ?public uint Symbol_Address;
? ?public SymbolType Symbol_Type;
? ?public ushort Symbol_Size;
? ?public String Symbol_Section;
};
?
?
接下來就是通過FileStream獲取.map文件中的信息,并定位至Image Symbol Table->Global Symbols,讀取Symbol Name、Value、Ov Type、Size、Object(Section)并賦值給symbol_table:
?
public void Create_Address_And_Size_Table(String filename){
? ? try
? ? {
? ?? ???uint i;
? ?? ???FileStream file_read = new FileStream(filename, FileMode.Open, FileAccess.Read);//新建文件流
? ?? ???filelist = File.ReadAllLines(filename, Encoding.Default);//讀取文件內(nèi)容所有行保存到字符串?dāng)?shù)組中。
? ?? ???for (i = 0; i <= filelist.Length - 1; i++)? ?? ?? ?? ???//定位到感興趣的位置
? ?? ???{
? ?? ?? ?? ? if (filelist[i].Contains("Global Symbols"))
? ?? ?? ?? ?{
? ?? ?? ?? ?? ?break;
? ?? ?? ?? ?}
? ?? ?? ?}
? ?? ???for (uint j = i; j <= filelist.Length - 1; j++)
? ?? ? {
? ?? ?? ? if (filelist[j].Contains("Object(Section)"))
? ?? ?? ?{
? ?? ?? ?? ?i = j + 1;
? ?? ?? ?? ?break;
? ?? ?? ?}
? ?? ? }
? ?? ???if (i < filelist.Length - 1)? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???//獲取信息
? ?? ???{
? ?? ?? ?? ?//Table_DeInit();
? ?? ?? ?? ?Get_Symbol_Data(i);
? ?? ?? ?}
? ?? ?? ?file_read.Close();
? ? }
? ? catch (Exception ex)
? ? {
? ?? ???MessageBox.Show(ex.Message);
? ???}
}
?
Get_Symbol_Data(i);就是負(fù)責(zé)將Image Symbol Table->Global Symbols中的Symbol Name、Value、Ov Type、Size、Object(Section)賦值給symbol_table。有兩點(diǎn)需要說明一下:
1)由于在Global Symbols中,
?
- ?
xxxxxx?-?Undefined?Weak?Reference
?
不包含有用信息,是需要被排除的,可以通過Contains("- Undefined Weak Reference")方法將其排除。
2)Image Symbol Table->Global Symbols中的Symbol Name、Value、Ov Type、Size、Object(Section)是通過空格將數(shù)據(jù)進(jìn)行分割,所以可以通過
?
- ?
Split(new?Char[]?{?'?'?},?StringSplitOptions.RemoveEmptyEntries);
?
就可以得到數(shù)據(jù)集。
void Get_Symbol_Data(uint index)函數(shù)如下:
?
private void Get_Symbol_Data(uint index)
{
? ???table_length = 0;
? ???while (index <= filelist.Length - 1)
? ? {
? ?? ???if (filelist[index].Equals(""))
? ?? ???{
? ?? ?? ???index++;
? ?? ?? ???continue;
? ?? ?? ?}
? ?? ???if(filelist[index].Contains("=") == false)
? ?? ???{
? ?? ?? ?? ?if (filelist[index].Contains("- Undefined Weak Reference"))??//排除- Undefined Weak Reference
? ?? ?? ???{
? ?? ?? ?? ?? ?index++;
? ?? ?? ?? ?? ?continue;
? ?? ?? ???}
? ?? ?? ? else
? ?? ?? ? {
? ?? ?? ?? ?? ? int str_index = 0;
? ?? ?? ?? ?? ? string[] split_str = filelist[index].Split(new Char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);//獲取數(shù)據(jù)集
? ?? ?? ?? ?? ?? ?? ?? ?
? ?? ?? ?? ?? ? symbol_table[table_length].Symbol_Name = split_str[str_index];
? ?? ?? ?? ?? ? str_index++;
? ?? ?? ?? ?? ? symbol_table[table_length].Symbol_Address = Convert.ToUInt32(split_str[str_index], 16);
? ?? ?? ?? ?? ? str_index++;
? ?? ?? ?? ?? ? if (split_str[str_index].Equals("Thumb"))
? ?? ?? ?? ?? ?{
? ?? ?? ?? ?? ?? ???symbol_table[table_length].Symbol_Type = SymbolType.Thumb_Code;
? ?? ?? ?? ?? ? }
? ?? ?? ?? ?? ?else if (split_str[str_index].Equals("Section"))
? ?? ?? ?? ???{
? ?? ?? ?? ?? ?? ? symbol_table[table_length].Symbol_Type = SymbolType.Section;
? ?? ?? ?? ???}
? ?? ?? ?? ???else if (split_str[str_index].Equals("Number"))
? ?? ?? ?? ???{
? ?? ?? ?? ?? ?? ???symbol_table[table_length].Symbol_Type = SymbolType.Number;
? ?? ?? ?? ?? ?}
? ?? ?? ?? ???else if (split_str[str_index].Equals("Data"))
? ?? ?? ?? ? {
? ?? ?? ?? ?? ?? ???symbol_table[table_length].Symbol_Type = SymbolType.Data;
? ?? ?? ?? ???}
? ?? ?? ?? ? str_index++;
? ?? ?? ?? ? if (split_str[str_index].Equals("Code"))
? ?? ?? ?? ???{
? ?? ?? ?? ?? ?? ???str_index++;
? ?? ?? ?? ?? ?? ???symbol_table[table_length].Symbol_Size = Convert.ToUInt16(split_str[str_index], 10);
? ?? ?? ?? ?? ?? ???str_index++;
? ?? ?? ?? ?? ?? ???symbol_table[table_length].Symbol_Section = split_str[str_index];
? ?? ?? ?? ?? ?}
? ?? ?? ?? ???else
? ?? ?? ?? ???{
? ?? ?? ?? ?? ?? ???symbol_table[table_length].Symbol_Size = Convert.ToUInt16(split_str[str_index], 10);
? ?? ?? ?? ?? ?? ???str_index++;
? ?? ?? ?? ?? ?? ???symbol_table[table_length].Symbol_Section = split_str[str_index];
? ?? ?? ?? ?? ?}
? ?? ?? ?? ?? ?? ?? ?? ?
? ?? ?? ?? ???table_length = table_length + 1;
? ?? ?? ?? ???index++;
? ?? ?? ?? ???if (table_length >= table_len)
? ?? ?? ?? ???{
? ?? ?? ?? ?? ?? ? break;
? ?? ?? ?? ?? ?}
? ?? ?? ? }
? ?? ?}
? ???else
? ???{
? ?? ?? ???break;
? ?? ?}
?
以上是class Get_Map_Address_And_Size_Table最主要的實(shí)現(xiàn)方法。通過這兩個(gè)方法,就可以得到.map文件中函數(shù)與全局變量的信息了。
?
2.3 class Get_Function_Address_And_Size_Table的實(shí)現(xiàn)——————獲取我們所需的函數(shù)列表
?
在得到含有函數(shù)與全局變量的信息的symbol_table后,我們需要得到我們感興趣的函數(shù)列表。在本上位機(jī)中,需要用戶新建一個(gè).function文件。在該文中包含有用戶需要調(diào)試的函數(shù)列表。一般只需直接復(fù)制.h文件中的函數(shù)申明即可。然后上位機(jī)通過該列表獲取函數(shù)名稱、參數(shù)、返回類型等參量,最后在symbol_table中查詢該函數(shù),并獲取其地址。以上就是class Get_Function_Address_And_Size_Table所要實(shí)現(xiàn)的目標(biāo)。在class Get_Function_Address_And_Size_Table中先定義
?
public struct Function
{
? ?? ?public String Function_List_Name;
? ?? ?public String Function_Name;
? ?? ?public uint Function_Address;
? ?? ?public String Function_Parameter1;
? ?? ?public String Function_Parameter2;
? ?? ?public String Function_Parameter3;
? ?? ?public String Function_Parameter4;
? ?? ?public String Function_Parameter5;
? ?? ?public String Function_Return;
? ?? ?public uint Function_Parameter_Number;
??};
?
以方便存儲所要調(diào)試函數(shù)信息。這里需要需要注意的是,由于C#中struct不能像C中struct一樣直接定義一個(gè)固定長度的數(shù)組,所以直接用Function_ParameterX這樣的笨辦法來定義5個(gè)函數(shù)參數(shù)信息。
?
在class Get_Function_Address_And_Size_Table中最重要的就是void Get_Need_Function_Table()函數(shù)。其獲取.function文件中的函數(shù)列表并解析處該列表函數(shù)名稱、參數(shù)、返回類型等參量,并賦值給function_table中。
?
private void Get_Need_Function_Table()
{
? ? uint index = 0;
? ? for (index = 0; index < table_length; index++)
? ?{
? ?? ???string[] split_str = filelist[index].Split(new Char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
? ?? ???uint str_index = 0;
? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???
? ?? ???function_table[index].Function_List_Name = filelist[index];? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?
? ?? ???if (split_str[str_index].Equals("unsigned") || split_str[str_index].Equals("signed"))? ?? ?? ?? ? //Function_Return
? ?? ???{
? ?? ?? ?? ? function_table[index].Function_Return = split_str[str_index] + " " + split_str[str_index + 1];
? ?? ?? ?? ? str_index = str_index + 2;
? ?? ?? ?}
? ?? ?? ?else
? ?? ???{
? ?? ?? ?? ? function_table[index].Function_Return = split_str[str_index];
? ?? ?? ?? ? str_index++;
? ?? ?? ? }
? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???
? ?? ?? ?if(split_str[str_index].Equals("*"))
? ?? ?? ?{
? ?? ?? ?? ? function_table[index].Function_Return = function_table[index].Function_Return + split_str[str_index];
? ?? ?? ?? ? str_index++;
? ?? ?? ?}
? ?? ?? ?if (split_str[str_index].Contains("*"))? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ? //Function_Name
? ?? ???{
? ?? ?? ?? ?function_table[index].Function_Return = function_table[index].Function_Return + "*";
? ?? ?? ?? ?function_table[index].Function_Name = split_str[str_index].TrimStart(new char[1] { '*' });
? ?? ?? ?? ?str_index++;
? ?? ???}
? ?? ? else
? ?? ?{
? ?? ?? ?? ?function_table[index].Function_Name = split_str[str_index];
? ?? ? }
? ?? ?? ?
? ?? ???string[] split_paramenter_str = new String[3];
? ?? ???split_paramenter_str = function_table[index].Function_Name.Split(new Char[] { '(' }, StringSplitOptions.RemoveEmptyEntries);
? ?? ???function_table[index].Function_Name = split_paramenter_str[0];
? ?? ?? ?? ?? ?
? ?? ???string[] paramenter = filelist[index].Split(new Char[] { '(' }, StringSplitOptions.RemoveEmptyEntries);//Function_Parameter_Number
? ?? ???String paramenter_string = paramenter[1];
? ?? ???paramenter_string = paramenter_string.TrimEnd(new char[2] { ')', ';' });
? ?? ???str_index = 0;
? ?? ?? ?if(paramenter_string.Equals("") || paramenter_string.Equals(" ") || paramenter_string.Equals("void"))
? ?? ?? ?{
? ?? ?? ?? ???function_table[index].Function_Parameter_Number = 0;
? ?? ?? ?? ???function_table[index].Function_Parameter1 = "";
? ?? ?? ?? ???function_table[index].Function_Parameter2 = "";
? ?? ?? ?? ???function_table[index].Function_Parameter3 = "";
? ?? ?? ?? ???function_table[index].Function_Parameter4 = "";
? ?? ?? ?? ???function_table[index].Function_Parameter5 = "";
? ?? ?? ? }
? ?? ?? ? else if(paramenter_string.Contains(","))
? ?? ?? ? {
? ?? ?? ?? ?? ?? ? string[] s = paramenter_string.Split(new Char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
? ?? ?? ?? ?? ?? ? switch(s.Length)
? ?? ?? ?? ?? ?? ? {
? ?? ?? ?? ?? ?? ?? ?? ???case 2: function_table[index].Function_Parameter1 = Get_Data_Kind(s[0]);
? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ? function_table[index].Function_Parameter2 = Get_Data_Kind(s[1]);
? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ? function_table[index].Function_Parameter3 = "";
? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ? function_table[index].Function_Parameter4 = "";
? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ? function_table[index].Function_Parameter5 = "";
? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ? function_table[index].Function_Parameter_Number = 2;
? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ? break;
? ?? ?? ?? ?? ?? ?? ?? ?case 3: function_table[index].Function_Parameter1 = Get_Data_Kind(s[0]);
? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???function_table[index].Function_Parameter2 = Get_Data_Kind(s[1]);
? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???function_table[index].Function_Parameter3 = Get_Data_Kind(s[2]);
? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???function_table[index].Function_Parameter4 = "";
? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???function_table[index].Function_Parameter5 = "";
? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???function_table[index].Function_Parameter_Number = 3;
? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???break;
? ?? ?? ?? ?? ?? ?? ?? ? case 4: function_table[index].Function_Parameter1 = Get_Data_Kind(s[0]);
? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?function_table[index].Function_Parameter2 = Get_Data_Kind(s[1]);
? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?function_table[index].Function_Parameter3 = Get_Data_Kind(s[2]);
? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?function_table[index].Function_Parameter4 = Get_Data_Kind(s[3]);
? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?function_table[index].Function_Parameter5 = "";
? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?function_table[index].Function_Parameter_Number = 4;
? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?break;
? ?? ?? ?? ?? ?? ?? ?? ???case 5: function_table[index].Function_Parameter1 = Get_Data_Kind(s[0]);
? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ? function_table[index].Function_Parameter2 = Get_Data_Kind(s[1]);
? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ? function_table[index].Function_Parameter3 = Get_Data_Kind(s[2]);
? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ? function_table[index].Function_Parameter4 = Get_Data_Kind(s[3]);
? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ? function_table[index].Function_Parameter5 = Get_Data_Kind(s[4]);
? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ? function_table[index].Function_Parameter_Number = 8;
? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ? break;
? ?? ?? ?? ?? ?? ???}
? ?? ?? ?? ?}
? ?? ?? ?? ?else
? ?? ?? ?? ?{
? ?? ?? ?? ?? ? function_table[index].Function_Parameter_Number = 1;
? ?? ?? ?? ?? ? function_table[index].Function_Parameter1 = Get_Data_Kind(paramenter_string);
? ?? ?? ?? ?? ? function_table[index].Function_Parameter2 = "";
? ?? ?? ?? ?? ? function_table[index].Function_Parameter3 = "";
? ?? ?? ?? ?? ? function_table[index].Function_Parameter4 = "";
? ?? ?? ?? ?? ? function_table[index].Function_Parameter5 = "";
? ?? ?? ?? ?}
??}
?
在得到function_table列表后,只需通過
?
for (uint i = 0; i < function_table.table_length; i++)
{
? ? index = map_table.Get_Index(function_table.function_table[i].Function_Name);
? ? addr = map_table.Get_Address(index);
? ? function_table.Set_Address(i, addr);
}
?
用以實(shí)現(xiàn)存儲全局變量的相關(guān)信息。
?
2.5 控制說明
?
2.5.1 命令字及其數(shù)據(jù)格式
函數(shù)發(fā)送命令字:?
函數(shù)返回值命令字:?
下位機(jī)接收超時(shí)命令字:?
?
有人會疑惑STM32的地址只有4字節(jié),為何在命令字中地址卻占用8字節(jié)?這要從不同類型數(shù)據(jù)轉(zhuǎn)換為byte說起。
?
將不同類型數(shù)據(jù)的函數(shù)參數(shù)轉(zhuǎn)換為byte的技巧就是使用聯(lián)合體。只要在聯(lián)合體中定義不同類型的變量與最大字長的char數(shù)組,就可以很容易的得到其在內(nèi)存中的分布。在一開始函數(shù)參數(shù)轉(zhuǎn)換時(shí),為了兼容double類型函數(shù)參數(shù),在“聯(lián)合體”中定義了double,導(dǎo)致其長度為8字節(jié)。而函數(shù)地址轉(zhuǎn)換也使用了這一方法,所以發(fā)送命令字中地址長度也變?yōu)?字節(jié)。需要注意的是,在C#中沒有聯(lián)合體這一概念,所以只能使用struct并指定變量起始地址以實(shí)現(xiàn)C的聯(lián)合體:
?
public struct TypeUnion
{
? ?[ ]
? ?public byte uc;
? ?[ ]
? ?public sbyte sc;
? ?[ ]
? ?public ushort us;
? ?[ ]
? ?public short ss;
? ?[ ]
? ?public uint ui;
? ?[ ]
? ?public uint pointer;? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ? //指針
? ?[ ]
? ?public int si;
? ?[ ]
? ?public float f;
? ?[ ]
? ?public double d;
}
?
由于不能定義char[8],所以之后還要使用static byte[] StructToBytes(object structObj)得到相應(yīng)變量的內(nèi)存分布byte[8]
?
2.5.2 調(diào)試函數(shù)與全局變量的發(fā)送流程
?
按下函數(shù)調(diào)試發(fā)送按鈕之后,會觸發(fā)void SendFunctionButton_Click(object sender, EventArgs e)函數(shù)。在該函數(shù)中主要流程是判斷串口是否開啟->函數(shù)參數(shù)類型轉(zhuǎn)換->CRC校驗(yàn)->超時(shí)判斷與重發(fā)。函數(shù)參數(shù)類型轉(zhuǎn)換主要由TypeUnion TypeTransfer(String type_s,String text_s)完成。該函數(shù)主要依據(jù)參數(shù)類型,將傳入的參數(shù)用 Convert.ToXXX(text_s, f_base)方法轉(zhuǎn)換為對應(yīng)的數(shù)據(jù),并直接賦值給TypeUnion,即一個(gè)聯(lián)合體變量,然后通過static byte[] StructToBytes(object structObj)得到內(nèi)存分布byte[8]。
?
而CRC校驗(yàn)則使用CRC16 CITT算法。在前49個(gè)字節(jié)填充完畢后,最后兩個(gè)字節(jié)先賦值為0,做一次CRC校驗(yàn),得到的數(shù)據(jù)再賦值給最后兩個(gè)字節(jié)。
?
2.5.3 函數(shù)返回值接收流程函數(shù)
?
在發(fā)送完函數(shù)調(diào)試命令后,上位機(jī)會自動(dòng)等待直至接收到下位機(jī)發(fā)送的回復(fù)或到達(dá)設(shè)置的超時(shí)時(shí)間。利用static object BytesToStuct(byte[] bytes, Type type)將前8個(gè)字節(jié)轉(zhuǎn)換為TypeUnion變量。而CRC校驗(yàn)則使用CRC16 CITT算法。在前8個(gè)字節(jié)填充完畢后做一次CRC校驗(yàn)。如果校驗(yàn)失敗則直接做一次超時(shí)處理,并在一定時(shí)間后重新發(fā)送函數(shù)調(diào)試命令。
?
2.5.4 超時(shí)與重傳處理
?
在實(shí)際的串口數(shù)據(jù)收發(fā)中,難免會遇到數(shù)據(jù)收發(fā)丟失或中斷。比如這次開發(fā)中使用虛擬串口收發(fā)數(shù)據(jù)就遇到數(shù)據(jù)丟失的情況:
?
?
?
?
明明監(jiān)控?cái)?shù)據(jù)都正確收發(fā),但就是會漏數(shù)據(jù),也不知怎么回事。沒辦法,只能做超時(shí)重發(fā)處理以應(yīng)對這種情況。在上位機(jī)中,主要通過函數(shù)bool Is_Timeout()來處理這一情況。
?
private bool Is_Timeout()
{
? ?bool timeout = false;
? ?ushort count_ = 0;
? ?while (SerialPort.BytesToRead < RETURN_MAX_LENTH)
? ?{
? ?? ?System.Threading.Thread.Sleep(1);? ?? ?? ?? ?? ?? ? //每隔1ms讀取數(shù)據(jù)是否都收到
? ?? ?count_++;
? ?? ?if (count_ > timeout_set)
? ???{
? ?? ???break;
? ???}
? ?}
??if (count_ < timeout_set)? ?? ?? ?? ?? ?? ?? ?? ?? ?? ? //未超時(shí)數(shù)據(jù)處理
{
? ???byte[] byteArray = new byte[RETURN_MAX_LENTH];
? ???SerialPort.Read(byteArray, 0, byteArray.Length);
? ???uint count = 0;
? ???for (uint i = 0; i < PARAMENT_MAX_LENTH; i++)? ?? ?? ???//收到8個(gè)字節(jié)都是0xFF,說明下位機(jī)未正確收到數(shù)據(jù)
? ? {
? ?? ? if (byteArray[i] == 0xFF)
? ?? ?{
? ?? ?? ? count++;
? ?? ?}
? ? }
? ? if (count >= PARAMENT_MAX_LENTH)
? ? {
? ?? ???timeout = true;
? ???}
? ???else
? ? {
? ?? ? if (function_send)? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ? //獲取函數(shù)返回值
? ?? ?{
? ?? ?? ? function_send = false;
? ?? ?? ? ushort crc1 = 0;
? ?? ?? ? crc1 = (ushort)byteArray[RETURN_MAX_LENTH - 2];
? ?? ?? ? crc1 = (ushort)(crc1 << 8);
? ?? ?? ? crc1 = (ushort)(crc1 | (ushort)byteArray[RETURN_MAX_LENTH - 1]);
? ?? ?? ? byte[] byte_Array = new byte[RETURN_MAX_LENTH - 2];
? ?? ?? ? for (uint i = 0; i < RETURN_MAX_LENTH - 2; i++)
? ?? ?? ?{
? ?? ?? ?? ? byte_Array[i] = byteArray[i];
? ?? ?? ?}
? ?? ?? ?CRC16 c = new CRC16();
? ?? ?? ?ushort crc = c.GetCRC16(byte_Array);
? ?? ?? ?if(crc == crc1)
? ?? ?? ?{
? ?? ?? ?? ?TypeUnion return_data = (TypeUnion)BytesToStuct(byte_Array, typeof(TypeUnion));
? ?? ?? ?? ?String s = TypeTransferToString(function_table.function_table[select_function_index].Function_Return, return_data);
? ?? ?? ?? ?RecivedTextBox.Text = s;
? ?? ?? ?}
? ?? ?? ?else
? ?? ?? ?{
? ?? ?? ?? ?timeout = true;
? ?? ?? ?}
? ?? ?}
? ?}
}
else? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ? //超過設(shè)置的超時(shí)時(shí)間,直接關(guān)閉串口并報(bào)錯(cuò)
??{
? ???timeout = true;
? ?? ?SerialPort.Close();
? ?? ?ControlSerialButton.Text = "打開串口";
? ?? ?COMComboBox.Enabled = true;
? ?? ?BaudRateComboBox.Enabled = true;
? ?? ?ParityBitsComboBox.Enabled = true;
? ?? ?StopBitComboBox.Enabled = true;
? ?? ?DataBitsComboBox.Enabled = true;
? ?? ?? ?? ?? ?
? ?? ? MessageBox.Show("通訊超時(shí)!已關(guān)閉串口!");
? ? }
? ?? ?? ?? ?return timeout;}
?
三、下位機(jī)的處理
?
3.1 接收處理
?
本來打算使用DMA+空閑中斷接收命令字,但考慮到有些低端的單片機(jī)沒有空閑中斷,同時(shí)實(shí)際使用中出現(xiàn)數(shù)據(jù)丟失會造成持續(xù)的等待,所以直接使用單字節(jié)中斷接收的方案。在接收到固定的字節(jié)后,標(biāo)志位data_recived置一,并將數(shù)據(jù)拷貝出來。
?
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?//接收中斷
{
? ?? ?unsigned char i = 0;
? ?? ???
? ?? ?HAL_TIM_Base_Stop_IT(&htim3);
? ?? ?__HAL_TIM_SET_COUNTER(&htim3, 0);
? ?? ?data[data_length] = recv_data;
? ?? ???
? ?? ?data_length++;
? ?? ???
? ?? ?if(data_length < MAX_RECIVE_LENGTH)
? ???{
? ?? ?? ?HAL_TIM_Base_Start_IT(&htim3);
? ?? ?}
? ???else
? ? {
? ?? ?? ? data_length = 0;
? ?? ?? ?? ?? ?? ?? ?? ?
? ?? ?? ? data_recived = 1;
? ?? ?? ?? ?? ?? ?? ?? ?
? ?? ?? ?for(i = 0;i < MAX_RECIVE_LENGTH;i++)
? ?? ???{
? ?? ?? ? r_data[i] = data[i];
? ?? ???}
? ???}
? ?? ?? ?? ?? ?
? ???HAL_UART_Receive_IT(&huart1, &recv_data, 1);
}
?
3.2 超時(shí)處理
?
由于在實(shí)際的數(shù)據(jù)收發(fā)中,會出現(xiàn)數(shù)據(jù)丟失而造成上位機(jī)發(fā)送完畢但下位機(jī)并未全部接受,從而下位機(jī)一直處于等待的情況。為了解決這一情況,引入一個(gè)定時(shí)為200Hz的定時(shí)器。在進(jìn)入接收中斷后,先關(guān)閉清空定時(shí)器,讀取接收的數(shù)據(jù)后再開啟定時(shí)。如果出現(xiàn)數(shù)據(jù)丟失而造成下位機(jī)等待的情況,則會引發(fā)定時(shí)中斷。在定時(shí)中斷內(nèi)直接清空接收計(jì)數(shù)器,并給上位機(jī)發(fā)送超時(shí)指令。
?
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) //超時(shí)中斷,超時(shí)時(shí)間為5ms,一旦超時(shí)就發(fā)送8字節(jié)0xFF
{
unsigned char i = 0;
HAL_TIM_Base_Stop_IT(&htim3);
__HAL_TIM_SET_COUNTER(&htim3, 0);
data_length = 0;
for(i = 0;i < PARAMENT_MAX_LENTH;i++)
{
returndata[i] = 0xFF;
}
crc = crc16(returndata, PARAMENT_MAX_LENTH);
returndata[PARAMENT_MAX_LENTH] = crc >> 8;
returndata[PARAMENT_MAX_LENTH + 1] = crc;
HAL_UART_Transmit(&huart1, returndata, 10, 0xFF);
}
?
3.3 函數(shù)指針
?
通過周期調(diào)用void Recived_Command_Handle(void)來實(shí)現(xiàn)上位機(jī)發(fā)送的函數(shù)調(diào)試命令字。
?
void Recived_Command_Handle(void)
{
? ?? ?unsigned char i = 0;
? ?? ?unsigned char j = 0;
? ?? ?? ?? ?? ?? ?? ?? ?
? ?? ?if(data_recived)
? ?? ?{
? ?? ?? ???data_recived = 0;
? ?? ?? ?? ?? ?? ?? ?? ?
? ?? ?? ???crc_16 = (r_data[49] << 8) | r_data[50];
? ?? ?? ?? ?? ?
? ?? ?? ???r_data[MAX_RECIVE_LENGTH - 2] = 0;
? ?? ?? ???r_data[MAX_RECIVE_LENGTH - 1] = 0;
? ?? ?? ???crc = crc16(r_data, MAX_RECIVE_LENGTH);? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?//CRC_CITT校驗(yàn)
? ?? ?? ?? ?? ?? ?? ?? ?
? ?? ?? ???if(crc == crc_16)
? ?? ?? ???{
? ?? ?? ?? ?? ?num = r_data[0];? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???//獲取參數(shù)數(shù)量
? ?? ?? ?? ?? ?? ?? ?? ?
? ?? ?? ?? ?? ?for(i = 0;i < PARAMENT_MAX_LENTH;i++)? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?//獲取地址
? ?? ?? ?? ?? ?{
? ?? ?? ?? ?? ?? ???addr.u_char[i] = r_data[1 + i];
? ?? ?? ?? ?? ? }
? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???
? ?? ?? ?? ?? ?for(i = 0;i < 5;i++)? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?//獲取參數(shù)
? ?? ?? ?? ???{
? ?? ?? ?? ?? ?? ?? ???for(j = 0;j < PARAMENT_MAX_LENTH;j++)
? ?? ?? ?? ?? ?? ?? ? {
? ?? ?? ?? ?? ?? ?? ?? ?? ?paramen[i].u_char[j] = r_data[(1 + PARAMENT_MAX_LENTH) + PARAMENT_MAX_LENTH*i + j];
? ?? ?? ?? ?? ?? ?? ???}
? ?? ?? ?? ?? ? }
? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???
? ?? ?? ?? ? if(addr.ul != 0)? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?//獲取返回值
? ?? ?? ?? ? {
? ?? ?? ?? ?? ?? ? for(i = 0;i < PARAMENT_MAX_LENTH;i++)
? ?? ?? ?? ?? ?? ?{
? ?? ?? ?? ?? ?? ?? ???return_data.u_char[i] = 0;
? ?? ?? ?? ?? ?? ? }
? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?
? ?? ?? ?? ?? ?? ?return_data = function(addr.ul,num,paramen);
? ?? ?? ?? ???}
? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?
? ?? ?? ?? ? for(i = 0;i < PARAMENT_MAX_LENTH;i++)
? ?? ?? ?? ? {
? ?? ?? ?? ?? ?? ?returndata[i] = return_data.u_char[i];
? ?? ?? ?? ???}
? ?? ?? ?? ???crc = crc16(return_data.u_char, PARAMENT_MAX_LENTH);? ?? ???
? ?? ?? ?? ???returndata[PARAMENT_MAX_LENTH] = crc >> 8;
? ?? ?? ?? ?? ?returndata[PARAMENT_MAX_LENTH + 1] = crc;
? ?? ?? ?? ?? ? HAL_UART_Transmit(&huart1, returndata, 10, 0xFF);? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?
? ?? ?? ?? ?}
? ?? ? }
}
?
其中函數(shù)實(shí)現(xiàn)由parameter_kind_union function(unsigned int function_addr,unsigned char paramenter_num,parameter_kind_union *paramenter)完成。
?
parameter_kind_union function(unsigned int function_addr,unsigned char paramenter_num,parameter_kind_union *paramenter)
{
? ? void *p = (void *)function_addr;
? ? parameter_kind_union return_data;
? ?? ???
? ? switch(paramenter_num)
? ?{
? ?? ?? ?case 0: return_data.ull = (*(unsigned int(*)())p)();
? ?? ?? ?? ?? ?? ???break;
? ?? ?? ?case 1: return_data.ull = (*(unsigned int(*)())p)(PARAMENT_TRANSFER(paramenter[0]));
? ?? ?? ?? ?? ?? ???break;
? ?? ?? ?case 2: return_data.ull = (*(unsigned int(*)())p)(PARAMENT_TRANSFER(paramenter[0]),PARAMENT_TRANSFER(paramenter[1]));
? ?? ?? ?? ?? ?? ???break;
? ?? ?? ?case 3: return_data.ull = (*(unsigned int(*)())p)? ?? ?(PARAMENT_TRANSFER(paramenter[0]),PARAMENT_TRANSFER(paramenter[1]),PARAMENT_TRANSFER(paramenter[2]));
? ?? ?? ?? ?? ?? ?? ?break;
? ?? ?? ? case 4: return_data.ull = (*(unsigned int(*)())p)(PARAMENT_TRANSFER(paramenter[0]),PARAMENT_TRANSFER(paramenter[1]),PARAMENT_TRANSFER(paramenter[2]),PARAMENT_TRANSFER(paramenter[3]));
? ?? ?? ?? ?? ?? ?? ? break;
? ?? ?? ???case 5: return_data.ull = (*(unsigned int(*)())p)(PARAMENT_TRANSFER(paramenter[0]),PARAMENT_TRANSFER(paramenter[1]),PARAMENT_TRANSFER(paramenter[2]),PARAMENT_TRANSFER(paramenter[3]),PARAMENT_TRANSFER(paramenter[4]));
? ?? ?? ?? ?? ?? ?? ???break;
? ?? ? }
? ?? ???
? ?? ?? ???return return_data;
}
?
- ?
#define?PARAMENT_TRANSFER(p)????????(*(volatile?unsigned?int*)((unsigned?int)&p))??
?
其操作含義如下:
?
1)&p含義為取變量p地址;
?
2)(unsigned int)&p)含義為將取得的地址強(qiáng)制轉(zhuǎn)換為unsigned int;
?
3)(volatile unsigned int*)((unsigned int)&p)含義為將數(shù)字轉(zhuǎn)換為unsigned int類型的指針;
?
4)*(volatile unsigned int*)((unsigned int)&p)含義為取得該地址內(nèi)的數(shù)據(jù);
可這樣會造成一個(gè)問題,這就是對于double和long類型的變量,其在取值時(shí)會造成錯(cuò)誤:
?
?
?
?
可以看到對于double類型,函數(shù)參數(shù)值只獲得了前4個(gè)字節(jié)的數(shù)據(jù),后4個(gè)字節(jié)數(shù)據(jù)丟失了。嘗試定義
?
- ?
#define?PARAMENT_TRANSFER(p)????????(*(volatile?unsigned?long?long*)((unsigned?int)&p))
?
可以正確獲得double參數(shù),但char等類型則不能正確獲取:
?
?
?
所以暫時(shí)使用第一種PARAMENT_TRANSFER定義。
?
(*(unsigned int(*)())p)()則為執(zhí)行函數(shù),類似于回調(diào)函數(shù)。通過它可以執(zhí)行指定的函數(shù)。
?
3.4 修改全局變量
通過void Set_Global_Data(unsigned int addr,unsigned char len,parameter_kind_union data)實(shí)現(xiàn)數(shù)據(jù)的寫入。而數(shù)組的寫入則是循環(huán)調(diào)用該函數(shù),并加入測試重傳功能。
評論
查看更多