在单片机中使用最多的通信接口基本就是串口了,说起串口就不得不提串口中最常用的一个函数就是打印函数printf()函数,在上位机上中这个函数直接从库函数中调用就可以了,那么在单片机中这个函数要怎么使用呢?能不能将这个函数和串口1对应起来,当然是有方法的。
下面就通过代码来演示一下如何在串口1上使用printf()函数的功能。
void uart_init(u32 bound)
{
//GPIO端口设置
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE); //使能USART1,GPIOA时钟
//USART1_TX GPIOA.9
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.9
//USART1_RX GPIOA.10初始化
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10
//Usart1 NVIC 配置
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3 ; //抢占优先级3
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
//USART 初始化设置
USART_InitStructure.USART_BaudRate = bound;//串口波特率
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式
USART_Init(USART1, &USART_InitStructure); //初始化串口1
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启串口接受中断
USART_Cmd(USART1, ENABLE); //使能串口1
}
首先初始化串口1所使用到的端口,将发送引脚设置为推挽输出模式,将接收引脚设置为浮空输入模式。这里串口使用中断来接收数据,所以还需要设置中断优先级,通过NVIC(嵌套向量中断控制器)来设置串口中断的优先级,接下来设置串口的波特率,字长为8位,1位停止位,无奇偶校验位,无硬件数据流控制端口,串口模式设置为收发模式。最后使能串口,并开启中断功能。
下面编写串口中断函数,用来接收数据
u8 USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.
//接收状态
//bit15, 接收完成标志
//bit14, 接收到0x0d
//bit13~0, 接收到的有效字节数目
u16 USART_RX_STA = 0; //接收状态标记
void USART1_IRQHandler(void) //串口1中断服务程序
{
u8 Res;
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断(接收到的数据必须是0x0d 0x0a结尾)
{
Res = USART_ReceiveData(USART1); //读取接收到的数据
if((USART_RX_STA & 0x8000) == 0) //接收未完成
{
if(USART_RX_STA & 0x4000) //接收到了0x0d
{
if(Res != 0x0a)USART_RX_STA = 0; //接收错误,重新开始
else USART_RX_STA |= 0x8000; //接收完成了
}
else //还没收到0X0D
{
if(Res == 0x0d)USART_RX_STA |= 0x4000;
else
{
USART_RX_BUF[USART_RX_STA & 0X3FFF] = Res ;
USART_RX_STA++;
if(USART_RX_STA > (USART_REC_LEN - 1))USART_RX_STA = 0; //接收数据错误,重新开始接收
}
}
}
}
}
接收数据时通过USART_RX_STA变量的最高两位表示接收数据的状态,接收数据以回车换行作为结束位,回车换行对应的数据为0x0D、0x0A,只有这两个数据挨着接收到之后才表示一组数据成功的接收到了,这里使用USART_RX_STA最高两位表示是否接收到了这两个结束标志。
串口设置好之后,接下来给串口1添加支持printf()函数的代码。
#if 1
#pragma import(__use_no_semihosting)
//标准库需要的支持函数
struct __FILE
{
int handle;
};
FILE __stdout;
//定义_sys_exit()以避免使用半主机模式
_sys_exit(int x)
{
x = x;
}
//重定义fputc函数
int fputc(int ch, FILE *f)
{
while((USART1->SR & 0X40) == 0); //循环发送,直到发送完毕
USART1->DR = (u8) ch;
return ch;
}
#endif
上面的两个函数是固定模式不需要修改,自己需要修改的是fputc()函数,在这个函数中将寄存器设置为串口1的寄存器,这样printf()函数在打印数据的时候,就会通过串口1将数据发送出去,如何这里的寄存器设置为了其他串口的寄存器,那么使用printf()函数打印的时候就会通过其他串口打印出去。重定义函数fputc()设置好之后,就可在程序中直接使用printf()函数打印了。
int main(void)
{
u8 t;
u8 len;
u16 times=0;
delay_init(); //延时函数初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
uart_init(115200);
LED_Init();
while(1)
{
if(USART_RX_STA&0x8000)
{
LED1=!LED1;
len=USART_RX_STA&0x3fff; //获取本次接收数据长度
printf("rn您发送的消息为:rn");
for(t=0;t USART_SendData(USART1,USART_RX_BUF[t]);//向串口1发送数据 while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);//等待发送完成 } printf("rn"); USART_RX_STA=0; } else { times++; if(times%5000==0) { printf("串口实验rn"); } if(times%300==0) printf("请输入数据,以回车键结束rn"); if(times%30==0) LED0=!LED0; delay_ms(10); } } } 在主函数中通过printf()打印提示语句,提示用户输入数据。当用户输入数据并以回车换行结束后,串口接收到数据就会将接收到的数据直接打印出来。 这样在单片机中,通过串口1就可以输出printf()函数打印的数据了。
上一篇:STM32单片机一个定时器输出不同频率PWM波
下一篇:STM32F103自定义的printf函数的实现
推荐阅读最新更新时间:2024-11-10 10:26
推荐帖子
- 嵌入式软件开发工程师
- 汉王科技股份有限公司嵌入式软件开发工程师-OCR软件部电子邮箱:yinsg@hanwang.com.cn发布日期:2007-03-21工作地点:北京市招聘人数:1工作年限:二年以上外语要求:英语薪水范围:面议学历:本科接受简历语言:中文或英文职位描述:职责描述:1、windows平台,应用软件开发;2、嵌入式平
- yangsiyan 嵌入式系统
- TI store购买开发板攻略
- 经常在TIstore买板子的你可能早就熟悉了整个购买过程,最近听说有了一点小变化,在这儿给大家分享下。如果你曾在TIstore购买板子的时候遇到过一些问题或疑问,欢迎跟帖分享有TI账号直接登录即可,没有的话需要先注册TI帐号,并登陆,然后在TIstore搜索你要购买的产品型号,如:CC3200-LAUNCHXL(以此板为例)点此查看我搜索到这块开发板的链接点击Buy加入购物车
- eric_wang TI技术论坛
- 关于触摸屏的触摸声音
- 我把WINCE600\\PUBLIC\\COMMON\\OAK\\DRIVERS\\WAVEUI目录下的四个文件替换掉了,为了保险起见,把找来的文件都转成了8bitPCM,1mono,11Khz。放进去后build-c然后sysgen,发现声音播不出来。开机音乐我也给替换了,16bitPCM,22Khz2stereo,可以播。那位兄弟晓得怎么回事?或者有不错的触摸屏声音送我一个,谢拉!QQ:18271320关于触摸屏的触摸声音MARK,学习下,帮顶下。在
- zoling 嵌入式系统
- 模拟电路与数字电路及其应用复习资料
- 数字电路及其应用复习资料2005-6-10(尽管其本非是专业课,但与专业“数字电路的模拟电路”相关当今时代,数字电路已广泛地应用于各个领域。本报将在“电路与制作”栏里,刊登系列文章介绍数字电路的基本知识和应用实例。 在介绍基本知识时,我们将以集成数字电路为主,该电路又分TTL和CMOS两种类型,这里又以CMOS集成数字电路为主,因它功耗低、工作电压范围宽、扇出能力强和售价低等,很适合电子爱好者选用。 介绍应用时,以实用为主,特别介绍一些家电产品和娱乐产品中的数字电
- fighting 模拟电子
- WINCE电源管理的问题
- 各位好友,我的系统进入SLEEP时会调用驱动里面的IOCTL_SET_POWER_STATE,但为何退出SLEEP时没有进入驱动里面的IOCTL_SET_POWER_STATE呢?谢谢了!WINCE电源管理的问题说明你的调用可能有问题呗Wince还是WindowsMobile?唤醒后可以正常工作吗?你的退出Sleep是什么意思,唤醒吗PM里有个函数叫updatdevicestate,PM在这个函数设备电源状态的更改,把调试信息打出来,看看PM有没有更改设备的状态wince4.2怎
- hjkl645 WindowsCE
- 晶体谐振器的工作原理
- 晶体谐振器的工作原理什么是石英石英的化学成分为SiO2,晶体属六方晶系的氧化物矿物,即低温石英(a-石英),是石英族矿物中分布最广的一个矿物种。广义的石英还包括高温石英(b-石英)。受压或受热能产生压电效应。石英晶体振荡器是利用石英晶体的压电效应制成的一种谐振器件,它的基本构成大致是:从一块石英晶体上按一定方位角切下薄片(常用晶片切型分为两种:AT切和BT切),在它的两个对应面上镀银作为电极,在每个电极上各焊一根引线接到管脚上,再加上封
- YXC扬兴晶振 分立器件
设计资源 培训 开发板 精华推荐
- L7808A 光控制器稳压器的典型应用 (Vo(min) = Vxx + VBE)
- 用于便携式消费电子产品的 1.8V DC 至 DC 单路输出电源
- 用于便携式的 2.85V DC 到 DC 单路输出电源
- AM1D-1209SH30-RZ 9V 1W DC-DC 转换器的典型应用
- 使用 Microchip Technology 的 TC9491B 的参考设计
- 使用 Microchip Technology 的 MIC2776L-YM5 的参考设计
- ATtiny85 Development Board SMD
- LP2951 固定输出 5V 稳压器的典型应用
- 使用 Analog Devices 的 LTC2945CUD-1 的参考设计
- TYPEC输入可调电源