
stm32怎么通过printf发送数据到上位机
这个需要通过STM32的串口。
①如果你的上位机是电脑,那么需要一个USB转TTL,TTL端接STM32串口。
②编写STM32串口驱动(这个很容易的,配置引脚和串口)
③通过标准库的printf或自己编写printf与串口驱动对接。
我以前做智能小车写了一份串口驱动,你可以自己看然后改一下:
(或者可以用库函数,百度很容易找到,我不太喜欢库函数)
/*******************usart_asm.s*******************/
;****usart驱动,汇编版****
USART1 EQU 0X40013800
USART2 EQU 0x40004400
DROS EQU 0X04
SROS EQU 0X00
;接口声明
EXPORT printChar
EXPORT printStr
EXPORT printNum
EXPORT SelectUsart
;接口声明,END
;引用声明
IMPORT Div_U32
;引用声明,end
;数据区
AREA USART_ADDRESS,DATA,READWRITE
Cur_Usart DCD USART2 ;当前usart地址存储,默认为usart2
Num_Buffer SPACE 12 ;定义10byte缓冲堆栈
;数据区,end
AREA USART_CODE,CODE,READONLY
;SelectUsart,选择Usart,参数2:usart器件代号(1=usart1,非1=usart2)
SelectUsart
STMFD SP!,{R1,LR} ;入栈
LDR R1,=Cur_Usart ;读入usart地址暂存器地址
CMP R0,#1
BNE U2
U1 LDR R0,=USART1
B SETSR
U2 LDR R0,=USART2
SETSR
STR R0,[R1]
LDMFD SP!,{R1,PC} ;出栈
;SelectUsart,end
;***printChar ,参数1:char
printChar
STMFD SP!,{R1-R2,LR} ;入栈
LDR R1,=Cur_Usart
LDR R1,[R1] ;载入Usart地址
CHR_WAIT
LDR R2,[R1,#SROS] ;读状态寄存器
TST R2,#0X80
BEQ CHR_WAIT ;等待上次传输完成
STRB R0,[R1,#DROS] ;写入
LDMFD SP!,{R1-R2,PC} ;出栈
;***printChar ,end
;***printStr ,参数1:str
printStr
STMFD SP!,{R1-R3,LR} ;入栈
LDR R1,=Cur_Usart
LDR R1,[R1] ;载入Usart地址
SEND_STR
LDR R2,[R1,#SROS]
TST R2,#0X80
BEQ SEND_STR ;等待上次传输完成
LDRB R3,[R0],#1 ;将指针(R0)处字符读入R3
STRB R3,[R1,#DROS];写入
CMP R3,#0
BNE SEND_STR;循环直到结束符'\0'
LDMFD SP!,{R1-R3,PC} ;出栈
;***printStr ,end
;printNum ,参数1:NUM,参数2:usart器件代号(1=usart1,非1=usart2)
printNum
STMFD SP!,{R1-R5,LR} ;入栈
LDR R1,=10 ;除数为10,被除数已在R0中
LDR R3,=Num_Buffer ;载入缓冲区首地址
LDR R4,=0
LDR R5,=0 ;负数指示器,1=负数
TST R0,#0x80000000
BEQ STR_NUM ;正数
EOR R0,#0xFFFFFFFF ;负数,反转
ADD R0,#1
LDR R5,=1
STR_NUM
BL Div_U32
ADD R2,R2,#0x30 ;转换为char
STRB R2,[R3],#1 ;余数存入缓冲区
ADD R4,R4,#1 ;计数+1
CMP R0,#0
BNE STR_NUM ;直到商为0
CMP R5,#1
LDR R1,=Cur_Usart
LDR R1,[R1] ;载入Usart地址
BNE SEND_NUM ;正数
LDR R2,='-'
STRB R2,[R3],#1 ;'-'号存入缓冲区
ADD R4,R4,#1 ;计数+1
SEND_NUM
LDRB R0,[R3,#-1]!
SEND_WAIT
LDR R2,[R1,#SROS] ;读状态寄存器
TST R2,#0X80
BEQ SEND_WAIT ;等待上次传输完成
STRB R0,[R1,#DROS] ;写入
SUBS R4,R4,#1
BNE SEND_NUM
LDMFD SP!,{R1-R5,PC} ;出栈
;printNum ,end
END
usart.h
/*********************************************
USART2{TX=PA2,Rx=PA3},USART1{TX=PA9,Rx=PA10}
*********************************************/
#ifndef USART_H_
#define USART_H_
#include "Common.h"
#include "I2C.h"
#include "SG90.h"
#include "SRF05.h"
#define USART_RECV_BUFF_SIZE 15
#define Pclk1_36MHz 36000000 //其他USART
#define Pclk2_72MHz 72000000 //USART1
#define USART_PSC 16 //Prescaler Value 时钟预分频
//#define CrLf {0x0D,0x0A,0x00}
void usart_init(void);
u32 calcBRRDiv(u32 BaudRate,u32 Pclk);
extern void SelectUsart(u32 Usart);//Usart为usart代号 1为usart1,非1为usart2
extern void printChar(char ch);//由汇编实现
extern void printStr(char * str);
extern void printNum(s32 num);
#ifdef DEBUG
void printf(char* s,...);
#endif
#endif
usart.c
#include "usart.h"
#include "stdarg.h"
//串口
/***私有函数声明***/
u32 calcBRRDiv(u32 BaudRate,u32 Pclk);
//------------------------------------------------------------------
//函数名:void usart_init(void)
//输入参数:无
//返回参数:无
//说明:初始化串口寄存器
//备注:DEBUG模式下将会初始化USART1
//------------------------------------------------------------------
void usart_init(void)
{
//Usart2 配置
USART2->BRR = calcBRRDiv(9600,Pclk1_36MHz);//(USART_BRR)
USART2->GTPR = USART_PSC/2;//(USART_GTPR)
USART2->CR1 = 0x0000202C;//(USART_CR1)0x000020EC
USART2->CR2 = 0; //(USART_CR2)
USART2->CR3 = 0; //(USART_CR3)
#ifdef DEBUG
//Usart1 配置
USART1->BRR = calcBRRDiv(9600,Pclk2_72MHz);//(USART_BRR)
USART1->GTPR = USART_PSC/2;//(USART_GTPR)
USART1->CR1 = 0x0000202C;//(USART_CR1)
#endif
}
#ifdef DEBUG
void printf(char* format,...)
{
va_list args;
va_start(args,format);
while(*format)
{
if(*format=='%')
{
switch(*++format)
{
case 'c':
printChar((char)va_arg(args,int));
break;
case 's':
printStr(va_arg(args,char*));
break;
case 'd':
printNum((s32)va_arg(args,s32));
break;
case '%':
printChar('%');
break;
}
}
else
{
printChar(*format);
}
format++;
}
va_end(args);
}
#endif
//------------------------------------------------------------------
//函数名:void USART2_IRQHandler(void)
//输入参数:null
//返回参数:null
//说明:串口接收中断服务
//------------------------------------------------------------------
const uchar BTCtrl_DataFrameHeader[5]={0xa5,0x5a,0x11,0xf5,0};//蓝牙控制数据帧头
uchar ser_dat[USART_RECV_BUFF_SIZE];//数据缓冲区
bool bProcessCompleted=true;//判断一帧数据是否处理完成,当一帧数据接收完毕,则该变量被置为false
enum BTProcessingFlag/*蓝牙数据接收模式*/
{
CheckingFrameHeader,//检测数据帧头
ReceivingData//接收数据包
};
void USART2_IRQHandler(void)
{
static uchar ser_x=0;
static uchar mat_x=0;//match x
static uchar sum=0;
static enum BTProcessingFlag dflag=CheckingFrameHeader;
if (bProcessCompleted)//!上一帧数据处理完成之后
{
if (USART2->SR & 1<<5)//!判断读寄存器是否非空
{
if (dflag==CheckingFrameHeader)
{
if (USART2->DR==BTCtrl_DataFrameHeader[mat_x])
{
mat_x++;
}
else
{
mat_x=0;
}
if (BTCtrl_DataFrameHeader[mat_x]==0)//!数据头结束,更换模式准备接收数据
{
dflag=ReceivingData;
ser_x=0;
mat_x=0;
sum=0;
}
}
else if (dflag==ReceivingData)
{
ser_dat[ser_x]=USART2->DR;
if (ser_x==USART_RECV_BUFF_SIZE-1)//!只接收USART_RECV_BUFF_SIZE字节
{
sum+=BTCtrl_DataFrameHeader[2];
sum+=BTCtrl_DataFrameHeader[3];
dflag=CheckingFrameHeader;//!切换接收模式
if (ser_dat[USART_RECV_BUFF_SIZE-1]==sum)//!数据检验
{
bProcessCompleted=false;//!数据正确,置接收完成标志
USART2->CR1 &= ~(1<<13);//!停止usart2
}
}
sum+=ser_dat[ser_x];//!数据验证
ser_x++;
}
}
}
}
//------------------------------------------------------------------
//函数名:u32 calcBRRDiv(u32 BaudRate,u32 Pclk)
//输入参数:BaudRate=波特率,Pclk=RCC时钟频率
//返回参数:应置入寄存器的值
//说明:计算相应波特率以及时钟频率对应的BRRDiv寄存器中应该填入的值
//备注:计算方法参照(分数波特率的产生)
//------------------------------------------------------------------
u32 calcBRRDiv(u32 BaudRate,u32 Pclk)
{
u32 div_mant;
u32 div_frac;
float frac;
div_mant=Pclk/(USART_PSC*BaudRate);
frac=(float)Pclk/(USART_PSC*BaudRate);
frac-=div_mant;
frac*=USART_PSC;
div_frac=(u32)frac;
div_frac+=(frac-div_frac)>=0.5?1:0;//四舍五入
if (div_frac==USART_PSC)//满USART_PSC进位
{
div_frac=0;
div_mant++;
}
div_mant<<=4;
div_mant|=div_frac;
return div_mant;
}