STM32 C++ 串口通信
- STM32 C++编程设置
- 注意
- main.cpp 代码
- 注意
- 运行结果
- 补充
- 补充二
- 补充三
- 源码
STM32 C++编程设置
参考:STM32的C++的简单实现(MDK5 STM32F103大容量系列) keil编译环境支持C++编译,所以keil不需要做任何修改
注意
涉及中断的服务函数必须用 extern “C” 作前缀,因为stm32的中断服务名是由汇编的启动代码内的向量表决定的,汇编不认得C++的函数名的链接符号。
main.cpp 代码
#include "math.h"
#include "string.h"
#include "ctype.h"
#include "led.h"
#include "delay.h"
#include "key.h"
#include "sys.h"
#include "usart.h"
#include "stdio.h"
extern u16 USART_RX_STA;
//#ifndef true
// #define true 1
//#endif
//#ifndef false
// #define false 0
//#endif
#define DEBUG_INFO
class USARTProc{
public:
USARTProc(){
m_usart=USART1;
m_bstate=false;
memset(receive_data, '\0', RECIVE_DATA_MAX_LEN);
}
USARTProc(USART_TypeDef* usart){
m_usart=usart;
m_bstate=false;
memset(receive_data, '\0', RECIVE_DATA_MAX_LEN);
}
int GetData() const{
return m_data;
}
bool GetState() const{
return m_bstate;
}
const char* GetReceiveStr(){
return receive_data;
}
USART_TypeDef* GetUsart(){
return m_usart;
}
// ͨ¹ý´®¿Ú»ñµÃÊý×Ö
void ReceiveNumber(){
while(1){
m_bstate=false;
if(USART_RX_STA & 0x8000){
int r, data; // 用于数据转换
u16 len;
bool bsign=true; // 数据符号 true --> +, false --> -
len = USART_RX_STA & 0x3fff;
r = len;
m_data = 0;
memset(receive_data, '\0', RECIVE_DATA_MAX_LEN);
for(int t = 0; t < len; t++){
// 若注释以下两行代码,会出现连续输出的BUG
USART_SendData(m_usart, USART_RX_BUF[t]);
while(USART_GetFlagStatus(m_usart, USART_FLAG_TC) != SET){}
receive_data[t] = USART_RX_BUF[t];
if(receive_data[t]=='-'){
bsign = false;
data = 0;
//}else if(isdigit(receive_data[t])){
}else{
data = (int)receive_data[t] - 48;
}
r = r - 1;
m_data = m_data + data * (pow(10.0, r));
}
if(!bsign)
m_data = -m_data;
USART_RX_STA = 0;
m_bstate=true;
#ifdef DEBUG_INFO
USARTx_printf(m_usart, "\r\n");
USARTx_printf(m_usart, "data=%d, bsign=%d, bstate=%d \r\n", m_data, bsign, m_bstate);
#endif
break;
}
}
}
private:
enum {RECIVE_DATA_MAX_LEN=60};
private:
char receive_data[RECIVE_DATA_MAX_LEN];
int m_data; // 数据
bool m_bstate; // 是否接受到数据
private:
USART_TypeDef * m_usart;
};
int main(void)
{
delay_init();
NVIC_Configuration();
uart_init(9600);
// LED_Init();
// KEY_Init();
USARTProc usartproc;
while(1)
{
usartproc.ReceiveNumber();
if(usartproc.GetState()){
USARTx_printf(usartproc.GetUsart(), "data=%d, str=%s \r\n", usartproc.GetData(), usartproc.GetReceiveStr());
}
}
}
注意
若仅改变上述代码,编译不会出错,但由于找不到中断函数的入口,会导致阻塞,需要在中断函数处添加 extern "C"
extern "C" void USART1_IRQHandler(void) // 其他入口函数同样处理
运行结果
补充
针对extern "C"
的另一种实现方式。
#ifdef __cplusplus
extern "C" {
#endif
void USART1_IRQHandler(void)
{
...
}
#ifdef __cplusplus
}
#endif
补充二
基于CPP编写程序时,不支持重定义fputc函数,所以不能使用printf,会导致阻塞。当使用到串口通信时,遇到开发板没有任何反应时,应当检查是否是串口程序的原因。
补充三
stm32f10x_conf.h为工程配置文件,为避免工程编译无用外设文件,stm32f10x_conf.h中注释了大部分外设头文件,所以当用到新的外设时,需要在该文件中修改对应包含的头文件。也可以直接在对应的文件中包含对应外设的头文件。
在用到新的外设时还需要在工程中添加对应的CPP文件。
当编译出现undefined symbol错误的时候,是由于找不到对应的实现,所以需要添加对应的c/cpp文件;
当编译出现identifier undefined错误的时候,是由于找不到对应的声明,所以需要添加对应的h文件;
若出现均正确添加但仍编译错误时,可考虑将工程中涉及到的源文件重新添加的方式纠错。
源码