導航:首頁 > IDC知識 > 半主機模式

半主機模式

發布時間:2020-08-19 23:45:06

1、能不能解釋一下下面程序是什麼意思啊拜託了,小弟很急的

是關於I/O的重定義

2、如何使用STM32F107的串口4

你的重定向有點問題啊,用下面這個吧,我發一個串口的文件給你,你打開看看,上面的四個串口都是同時在運行的
有什麼不明的看一下上傳的文件,如果還有問題再交流

重定向程序

#if 1
//可以在這里寫
//#define USARTx 為哪個串口,我用的方法是,當用到哪個串口時,就把哪個串口賦給USARTx
//例如要用到串口4,那就寫成
//USARTx =UART4 ;
//不過你得先定義一下USARTx 這個變數,定義為32位的,因為UART4是指向一個32位的地址的,上面的賦值只是把
//UART4指向的地址賦給USARTx 而已,其它串口的使用也是一樣的

#pragma import(__use_no_semihosting)
/******************************************************************************
*標准庫需要的支持函數
******************************************************************************/
struct __FILE
{
int handle;
/* Whatever you require here. If the only file you are using is */
/* standard output using printf() for debugging, no file handling */
/* is required. */
};
/* FILE is typedef』 d in stdio.h. */
FILE __stdout;

/// <summary>
/// 定義_sys_exit()以避免使用半主機模式
/// </summary>
/// <param name="x"></param>
/// <returns></returns>
_sys_exit(int x)
{
x = x;
}

int fputc(int ch, FILE *f)
{
USARTx->DR = (u8) ch;

/* Loop until the end of transmission */
while(USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET)
{
}

return ch;
}

/*******************************************************************************
* 函數名 :fgetc
* 輸 入 :
* 輸 出 :
* 功能說明 :
* 重定義getc函數,這樣可以使用scanff函數從串口1輸入數據
*******************************************************************************/
int fgetc(FILE *f)
{
/* 等待串口1輸入數據 */
while (USART_GetFlagStatus(USARTx, USART_FLAG_RXNE) == RESET);

return (int)USART_ReceiveData(USARTx);
}

#endif

3、怎麼解決STM32中不能使用printf函數的問題

簡單地說:想在mdk 中用printf,需要同時重定義fputc函數和避免使用semihosting(半主機模式),
標准庫函數的默認輸出設備是顯示器,要實現在串口或LCD輸出,必須重定義標准庫函數里調用的與輸出設備相關的函數.
例如:printf輸出到串口,需要將fputc裡面的輸出指向串口(重定向),方法如下:
#ifdef __GNUC__
/* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
set to 'Yes') calls __io_putchar() */
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */
PUTCHAR_PROTOTYPE
{
/* Place your implementation of fputc here */
/* e.g. write a character to the USART */
USART_SendData(USART1, (uint8_t) ch);
/* Loop until the end of transmission */
while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
return ch;
}
因printf()之類的函數,使用了半主機模式。使用標准庫會導致程序無法運行,以下是解決方法:
方法1.使用微庫,因為使用微庫的話,不會使用半主機模式.
方法2.仍然使用標准庫,在主程序添加下面代碼:
#pragma import(__use_no_semihosting)
_sys_exit(int x)
{
x = x;
}
struct __FILE
{
int handle;
/* Whatever you require here. If the only file you are using is */
/* standard output using printf() for debugging, no file handling */
/* is required. */
};
/* FILE is typedef』 d in stdio.h. */
FILE __stdout;
如果使用的是MDK,請在工程屬性的「Target「-》」Code Generation「中勾選」Use MicroLIB;今天參考了一下論壇,使用微庫可以很好的解決這個問題。
2.另一種方法:(其實大同小異)
需要添加以下代碼
(論壇里應該有完整介紹這個的帖子,但是我沒搜到,也許是沉了。)
#pragma import(__use_no_semihosting)
/******************************************************************************
*標准庫需要的支持函數
******************************************************************************/
struct __FILE
{
int handle;
/* Whatever you require here. If the only file you are using is */
/* standard output using printf() for debugging, no file handling */
/* is required. */
};
/* FILE is typedef』 d in stdio.h. */
FILE __stdout;

/// <summary>
/// 定義_sys_exit()以避免使用半主機模式
/// </summary>
/// <param name="x"></param>
/// <returns></returns>
_sys_exit(int x)
{
x = x;
}

int fputc(int ch, FILE *f)
{
//USART_SendData(USART1, (u8) ch);
USART1->DR = (u8) ch;

/* Loop until the end of transmission */
while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET)
{
}

return ch;
}
semihosting的作用,介紹如下
Semihosting is a mechanism for ARM targets to communicate input/output requests
from application code to a host computer running a debugger. This mechanism could be
used, for example, to allow functions in the C library, such as printf() and scanf(), to use the screen and keyboard of the host rather than having a screen and keyboard on the target system.
This is useful because development hardware often does not have all the input and
output facilities of the final system. Semihosting allows the host computer to provide these facilities.
Semihosting is implemented by a set of defined software interrupt (SWI) operations.
The application invokes the appropriate SWI and the debug agent then handles the SWI
exception. The debug agent provides the required communication with the host.
In many cases, the semihosting SWI will be invoked by code within library functions. The application can also invoke the semihosting SWI directly. Refer to the C library descriptions in the ADS Compilers and Libraries Guide for more information on support for semihosting in the ARM C library.
按我的理解,這個模式是用來調試的,通過模擬器,使用主機的輸入輸出代替單片機自己的,也就是說即便單片機沒有輸出口也能printf到電腦上。反過來,由於這個模式更改了printf()等的實現方式,輸入輸出就不走單片機的外設了,所以只重定義fputc不起作用。

用代碼關閉此模式後,需要同時更新一下__stdout 和__stdin 的定義,所以有後面的語句。

以上僅為個人理解,如有錯誤請指正。

另外,勾選microlib之後,也許編譯的時候就不把開啟semihosting的文件包進去了,所以沒事。

C庫函數重定向:
用戶能定義自己的C語言庫函數,連接器在連接時自動使用這些新的功能函數。這個過程叫做重定向C語言庫函數,如下圖所示。
舉例來說,用戶有一個I/O設備(如UART)。本來庫函數fputc()是把字元輸出到調試器控制窗口中去的,但用戶把輸出設備改成了UART埠,這樣一來,所有基於fputc()函數的printf()系列函數輸出都被重定向到UART埠上去了。
下面是實現fputc()重定向的一個例子:
externvoidsendchar(char*ch);
intfputc(intch,FILE*f)
{/*e.g.writeacharactertoanUART*/
chartempch=ch;
sendchar(&tempch);
returnch;

這個例子簡單地將輸入字元重新定向到另一個函數sendchar(),sendchar()假定是個另外定義的串口輸出函數。在這里,fputc()就似乎目標硬體和標准C庫函數之間的一個抽象層。

4、STM32調試求助,無法進入main函數

昨天調試STM32程序,以前使用的是MDK3.40的版本,把版本升了下級,升到了MDK4.10,裝好後,一運行,哈哈,新版本給人的感覺就是不一樣啊,很爽,較之前有很多改進,把自己以前的程序打開,編譯運行發現程序調試時無法進入Main函數,弄了很久,很是郁悶啊,最後還是在ourdev的壇子里,找到了同樣問題的解決方法, 以下是壇子裡面的帖子,我把他貼出來了.

sdc666 :
請問高手,我在調試我的STM32F101c8t6時,遇到一個問題,因為我要調試串口,我在main.c中添加了#include <stdio.h> ,編譯可以通過,但是當我用jlink硬體調試時,一開始就停在了 " 0x08001460 BEAB BKPT 0xAB";並且無法向下運行. 請問高手,這個問題的原因是什麼?怎麼解決? 謝謝!
_sys_open:
0x08001450 B50E PUSH {r1-r3,lr}
0x08001452 E9CD0100 STRD r0,r1,[sp,#0]
0x08001456 F000FAF9 BL.W strlen (0x08001A4C)
0x0800145A 9002 STR r0,[sp,#0x08]
0x0800145C 4669 MOV r1,sp
0x0800145E 2001 MOVS r0,#0x01
0x08001460 BEAB BKPT 0xAB
0x08001462 BD0E POP {r1-r3,pc}

pldjn :
應該是項目設置的問題,檢查一下你的設置.

sdc666:
pldjn 你好,能詳細指點以下么?應該怎樣設置? 這個程序是我該的,本來是沒有#include <stdio.h>,我添加串口後因為需要標准庫函數,所以才加上的. 是不是還要設置編譯環境? 謝謝.

pldjn :
你用J-Flash打開你的HEX文件看看編譯的是否是對的.不用自動下載使用J-flash燒進去調一下試試.

dragonwww:
我也遇到同樣問題,我是調用printf時出現的這個錯誤,我已經把putchar重定位了,不知道為何還是出錯,求解,THX!

yugen:
那是因為你使用了printf之類的庫函數,需要編寫_sys_exit()之類底層函數。照你的提示看,也許是_sys_open()沒寫。_sys_xxx之類的的只要寫個空函數就行了。

dragonwww:
to yugen:
能否說的再仔細些,如果自己編寫個空函數應該放在哪裡?函數定義格式是什麼樣的呢?
納悶的是以前也用過printf,沒出現這個提示啊。

PZLPDY:
5樓的應該不是這樣吧?
應該是你沒有選中微庫造成的。這個問題昨天我遇到過。在工程的設置選項里把微庫勾上就OK了

dragonwww:
to PZLPDY:
蒼天啊,果然如你所說,把微庫勾上就OK了,奇怪了為什麼以前用的的時候沒報錯呢?以前也沒選微庫啊!

yugen:
因printf()之類的函數,使用了半主機模式。使用微庫的話,不會使用半主機模式,所以就沒有問題。
添加下面代碼,就可以使用標准庫了:
#pragma import(__use_no_semihosting)
_sys_exit(int x)
{
x = x;
}
struct __FILE
{
int handle;
/* Whatever you require here. If the only file you are using is */
/* standard output using printf() for debugging, no file handling */
/* is required. */
};
/* FILE is typedef』 d in stdio.h. */
FILE __stdout;

dragonwww:
yugen是高手啊,再請教一下:
1.何為「半主機模式」?與 非半主機模式有何區別?
2.你的這段代碼需要放在那個文件里?自己的main函數所在的文件嗎?
3.看到代碼實現了_sys_exit,那我提示錯誤的_sys_open()不用實現嗎?
請指教,多謝!

yugen:
你說的問題都可以在"RealView® 編譯工具庫和浮點支持指南"書中找到,網上有下,我就不復制了。書有中文的。realview編譯器有好幾本書,都有中文。

5、C++程序無法進入到main函數,代碼、運行結果如下

func函數內的p未指向任何有效的內存空間就進行解引用,會導致程序崩潰。

#include <iostream>
using namespace std;

int *func()
{

    int *p = new int[1000]; //先分配1000個int的內存空間並令p指向它
    int n = 0;
    for (int i = 0; i < 1000; i++)
    {
        if (((i % 7 == 0) || (i % 11 == 0)) && !(i % 7 == 0 && i % 11 == 0))
        {
            *(p+n) = i;
            n+=1;
        }
    }
    return p;
}

int main()
{
    cout << "debug info" << endl;
    int *pointer;
    pointer = func();
    for (int i = 0; i < 1000; i++)
    {
        cout << *(pointer + i) << endl;
    }
    delete[] pointer; //使用完後釋放內存空間
    return 0;
}

6、stm32 f407 串口scanf如何接收數據的常式

1,使用半主機模式, #pragma import(__use_no_semihosting) ,
2. 聲明 struct __FILE {int handler;}
3. 重定義 FILE __stdin;
4. 實現 int fgetc(FILE*); 從串口中讀取一個字元,
5.以上步驟 + 調試。

7、STM32 DMA 內存地址不會設。

stm32手冊里有一塊是關於外設地址,還有一般全局變數地址以及局部變數地址的介紹,如果使用dma的話,可以把地址盡量往後設,比如 0x40012440,這就已經是離你會用的那些變數的地址很遠很遠了,不會有沖突。

8、stm32F030F4P6的晶元 串口通信不成功代碼在圖里

建議串口連接到PC進行調試。可以先進行單元測試,測試成功後再去進行業務實現。

直接printf,看看PC端是否能收到。

直接getchar看看stm32端是否能收到。

最後,附上我用的重定義的代碼,僅實現了fputc,實測可用。

#define PRINT_UART USART1
#pragma import(__use_no_semihosting)                         
struct __FILE //標准庫需要支持的函數

int handle; 
}; 
typedef struct __FILE FILE;
FILE __stdout;        
void _sys_exit(int x) //避免使用半主機模式

x = x; 

int fputc(int ch, FILE *f)//重定義fputc函數

while((PRINT_UART->ISR&0X40)==0);//循環發送,直到發送結束
PRINT_UART->TDR = (u8) ch;      
return ch;
}

9、調試的時候為什麼要禁用半主機模式

調試的時候為什麼要禁用半主機模式
在部署生產應用程序或進行任何性能測量之前,始終記住禁用調試模式。如果啟用了調試模式,應用程序的性能可能受到非常大的影響。

10、scnprintf這個函數怎麼在網上都搜不到

#ifdef __GNUC__
/* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
set to 'Yes') calls __io_putchar() */
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */
PUTCHAR_PROTOTYPE
{
/* Place your implementation of fputc here */
/* e.g. write a character to the USART */
USART_SendData(USART1, (uint8_t) ch);
/* Loop until the end of transmission */
while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
return ch;
}
因printf()之類的函數,使用了半主機模式。使用標准庫會導致程序無法運行,以下是解決方法:
方法1.使用微庫,因為使用微庫的話,不會使用半主機模式.
方法2.仍然使用標准庫,在主程序添加下面代碼:
#pragma import(__use_no_semihosting)
_sys_exit(int x)
{
x = x;
}
struct __FILE
{
int handle;
/* Whatever you require here. If the only file you are using is */
/* standard output using printf() for debugging, no file handling */
/* is required. */
};
/* FILE is typedef』 d in stdio.h. */
FILE __stdout;

與半主機模式相關的知識