1、为什么要用串口?

     自上一篇写的时间是1月20号,今6月7号了,半年没更新了。

这半年发生了什么?过完年就去找公司实习,在那里自我感觉进步很大。其实在公司大多都是自学,师傅基本不会给你说什么。但这并不能说明你的师傅对你不好,带我的那个师傅只比我高一届,但他的水平比我高的好多届。他也是自学,也没人告诉他该怎么做,因为老板也不太懂。所以自学能力很重要,当然有人带你的话,这样会更好。

      不说这些了,串口在调试的时候作用非常大。也学我们在学51的时候,只是将程序下载到开发板,看看是否能运行起来,通过数码管将结果显示出来,从而就知道程序设计的正确性。以前我也是这样做的,没什么不好。

在公司实习的时候,他们调试都是使用串口打印输出信息,观察程序从上电、初始化、运行数据什么的全部都显示到PC机上。然后再一句一句分析它的打印信息,从而找到出错的源头。这使我对串口的认识有更深了一步,所以我决定在学习STM32的时候,开发流程跟在公司学的方法一样——使用串口,观察打印信息。

2、STM32跟PC机(也就是电脑)如何连接

       我的STM32F103C8T6只是裸板,没有串口芯片,当然用的也是学生机——笔记本电脑,同样也没串口。

解决办法1、买一块 MAX3232转接板+一条USB转串口线 +邮费=30块左右

              2、只需要买一块PL2303的USB转接板。这样就将第一种的转接板和连接结合到一起了。

不过我用的是第一种,MAX3232+USB的串口线  ,为什么不用方便的2种?

max3232对于没有串口的开发板可以充当电平转换芯片,如何开发板有了电平转换芯片,我便使用USB转串口线经行连接,这样便灵活了。第二种只是用在既没转换芯片也没USB转串口的情况,不过对于最小系统板来说,它既可以下载程序,又可以当做串口来调试。至于台式机就不需要USB转串口线了,普通串口线即可。

                连接示意如下所示:

3、代码分析

       再写这里之前,应该已经学过模块化编程了,STM32的每个XXX.c 和xxx.h 这都是模块化编程。良好的程序,与其好的代码风格有关。你的代码风格跟你接触教你写代码的有很大关系。以前刚刚学习单片机编程,我还不信,现在我承认,跟教我单片机的老师风格有些像。

 

       这里我做的是一个串口发送数据到PC机的例子:

       要让STM32能够顺利发出数据,要进行如下配置

PA9,PA10管脚要配置,   USART也需要配置波特率,数据有几位,停止位,数据流等。

USART和uart有什么区别   USART在做串口时,两者并不区别,但是USART有SPI的功能。还有串口通信为什么要配置波特率,停止位,硬件数据留这些,以前我也没想过,现在只觉得协议这个东西,是一个好的标准。

        建立一个usart_debug.c的文本,内容如下

#include"usart_debug.h"

void GPIO_Configuration(void)

{

GPIO_InitTypeDef  GPIO_InitStructure;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//使能UASRT的时钟

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//使能GPIOA的时钟,开始的时候,我没用这句话,调了两天,跟源码一句一句比才知道

RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);

GPIO_InitStructure.GPIO_Pin =GPIO_Pin_9;

GPIO_InitStructure.GPIO_Speed= GPIO_Speed_50MHz; //波特率较高,IO翻转需较高频率

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出;我看网上有人说设置成GPIO_Mode_Out_PP普通推挽输出也行,但实践出真知,我试了发送是乱码。;

GPIO_Init(GPIOA,&GPIO_InitStructure);

 

GPIO_InitStructure.GPIO_Pin =GPIO_Pin_10;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //配置成浮空输入,既然是输入所以就不用配置IO口的频率了

GPIO_Init(GPIOA,&GPIO_InitStructure);

}

 

void USART1_config(void)

{

USART_InitTypeDef     USART_InitStructure;

USART_InitStructure.USART_BaudRate= 115200;     //配置波特率

USART_InitStructure.USART_WordLength = USART_WordLength_8b; //配置数据位

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);

 

USART_Cmd(USART1, ENABLE);

}

//这段很重要,如果要使用printf函数打印信息,需要加fputc函数,就需要对printf函数重定向到串口,以前工作中他们老是提重定向,什么串口重定向,USB重定向什么的,我也是云里雾里,如今给我的感觉就是将上层函数实现对底层硬件的操作

int  fputc(int ch,  FILE*f){

while(USART_GetFlagStatus(USART1, USART_FLAG_TC) !=SET); //网上的一些函数里面是没有这一句代码,如果不加的话,打印时第一个字符就会没有,原因据说是硬件复位后,USART_FLAG_TC被置一了,而要发送数据必须让其为底才可以,一表示数据发送发出的标志,也可以用这样一句USART_ClearFlag(USART2,USART_FLAG_TC);清楚标准位。可是我没这样做一样发成功了,这个疑惑以后再想明白。

USART_SendData(USART1, (uint16_t)ch);

 

while(USART_GetFlagStatus(USART1, USART_FLAG_TC) !=SET);

return ch;

 

}

void usart_debug_config(void)  //提供给main函数调用的串口配置函数

{

GPIO_Configuration(); //IO口配置

USART1_config();   //串口配置

}

 

 

还就是usart_debug.h

#ifndef __usart_debug_H

#define    __usart_debug_H

 

#include "stm32f10x.h"

#include

 

void usart_debug_config(void);

int fputc(int ch, FILE *f);

 

 

#endif // __USART1_H

 

 

 

 

 

       main函数:

这里使用两种方式一种是 使用普通的方式发送,另一种使用printf函数

其实还有一种USART_printf函数来实现,这里不做介绍。有空看看区别一下printf和usart_printf,据说是支持格式多少的问题

 

#include"stm32f10x.h"

#include"usart_debug.h" //包含main函数里的调用函数

int main(void)

{

 

unsigned char TxBuf1[100] ={"发送字符串!!!\r\n"};

int  i;

SystemInit();

usart_debug_config();

for( i = 0; TxBuf1[i] != '\0'; i++)

{

while(USART_GetFlagStatus(USART1, USART_FLAG_TC)==RESET);//这里跟分析fputc时是一样的

USART_SendData(USART1 , TxBuf1[i]);//发送字符数组里的单个字符

while(USART_GetFlagStatus(USART1, USART_FLAG_TC)==RESET);

}

 

printf("hello world!  世界你好! \r\n"); //调用printf函数

while(1)

{

;

}

 

}

 

 

仿真及调试

程序编好之后,在target option里要选择 USE microLIB (keil自带的微库),这是使用非标准C库,在编译链接是,将我们编写的fputc函数作为编译的首选,否则就会编译stdio.h里的fputc函数。

写到这里我发现我这个代码感觉不是很好,使用微库而不用标准C库,应该会有影响,我瞬间就明白了他们为什么要自己编写支持输出格式很少的的USART_printf函数了,后面目测我也会使用这个函数。

一个好的程序代码就是结构健全,BUG很少。把简单做到极致



在KEIL里继续软件仿真

仿真和下载时要注意的是,仿真要选USE Simulation  而下载要选右边的JTAG。。。。

然后点击debug 进入调试界面

 

view--->serial windos -->UART 1

全速运行 其结果如下:

串口发送数据就到此为止。

串口接收数据

这儿写的跟上面的已经没有关系了,不要搞混。

关于从PC机发送数据到STM32,这一部分则需要中断来实现,因为我们不需要时时刻刻都来检测外部是否发出数据给STM32,因此只要有数据来,就触发中断。这里就需要配置NVIC了

void NVIC_Config(void)

{

NVIC_InitTypeDef NVIC_InitStructure;

 

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);      //优先组为2

NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;  //打开USART中断通道

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3; //抢占优先级

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;          //子优先级

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;     //中断通道使能

NVIC_Init(&NVIC_InitStructure);

 

USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);    //串口接收中断使能

 

USART_Cmd(USART1, ENABLE);

}

 

 

其他配置比如串口复用到IO配置,串口时钟配置,和发送数据是一样的。

 

 

串口中断处理函数:

 

 

void USART1_IRQHandler(void)

{  int RX_status;  //自己定义一个标志位

RX_status = USART_GetFlagStatus(USART1, USART_FLAG_RXNE);//读取接收数据标志位,如果装好了一帧数据则硬件将其置一。

if(RX_status == SET) {

USART_SendData(USART1 , USART_ReceiveData(USART1));//将收到的数据再由STM32发送给PC机。

while(USART_GetFlagStatus(USART1, USART_FLAG_TC)==RESET);//等待发送完成。

 

}

}

       串口的发送接收大致如此,还是要搞懂什么数据位,硬件流,停止位,校验位什么,一个东西既然出现了就要好好分析出现的意义。想到了今天给电脑拆机清灰,电脑最好两年清一次。反正每次上螺丝都会多出那么一两个来,是不是可以不用要?

       肯定不是,生产商肯定也知道节约成本什么,他们的结构工程师也知道PCB上开一个螺丝孔也是要收钱的。所以每一颗螺丝都有它的意义,所以什么校验位,停止位也有他的意义,即便我们不使用。其实剩的螺丝我也扔了,完全不知道上在哪儿!


关键字:STM32  串口 引用地址:STM32之串口的使用

上一篇:STM32F103程序设计-9-USB转TTL串口(收发)
下一篇:STM32串口循环队列数据处理案例

推荐阅读

智能手环经过几年的发展,如今已经不是什么新鲜产品了。在2017年第一季度,小米手环销量超越 Fitbit,成为全球第一可穿戴设备厂商。并非小米手环有什么颠覆性的创新,而仅是因为其高性价比的销售策略打开了市场。然而智能手环市场低价竞争趋势让许多智能手环巨头公司被打得措手不及。 不久前,可穿戴设备厂商Jawbone进入破产清算;智能手表鼻祖Pebble在...
Power Integrations(PI)于2019年7月27日发布了结合PowiGaN技术的全新InnoSwitch™3系列恒压/恒流离线反激式开关电源IC,利用GaN(氮化镓)技术,让InnoSwitch的产品在整个负载范围内提供95%的高效率转换,并且在密闭适配器内不使用散热片的情况下可提供100 W的功率输出。这款产品的发布日期专门选在了PI二季度财报当天,足见该技术对PI未来的重要性。P...
众所周知,英国的ARM公司是嵌入式微处理器世界当中的佼佼者。ARM一直以来都是自己研发微处理器内核架构,然后将这些架构的知识产权授权给各个芯片厂商,精简的CPU架构,高效的处理能力以及成功的商业模式让ARM公司获得了巨大的成功,使它迅速占据了32位嵌入式微处理器的大部分市场份额。目前,随着对嵌入式系统的要求越来越高,作为其核心的嵌入式微处理器...
现在社会发展迅速,人们脱离了原始社会亲力亲为的状态,生活的很多方面都采取了智能化的手段。而家用机器人就是这智能化社会迅速发展的一个标志。家用机器人的主要功能就是为人类服务,是一种服务机器人。它主要从事家庭服务,如家庭清洁、维护、保养、运输、修理等。家用机器人由于其用途的不同,它的种类也有很多。接下来讲解一下家用机器人的种类有哪些...

史海拾趣

问答坊 | AI 解惑

求助

我想做一个电源指示电路,要求任意一路或多路出现断路,实现报警功能。六路电源分别是+5v,+15v,+12v,+130v,+15v,-15v。谢谢各位大虾!…

查看全部问答∨

等精度数字频率计是什么来得?

如题。最好给些参考知料。谢谢各位了。…

查看全部问答∨

关于PIC MPLAB 为什么编译失败不提示错误位置(无错误报告)

mplab+picc编译器 编译失败后 为什么不提示错误位置,错误需要自己一个字一个字的找,该怎么设置编译器选项呢,刚接触PIC请各位帮忙解释一下  …

查看全部问答∨

WIFI驱动对密码错误的连接的处理

用微软自带的WIFI配置程序,先用错误的密码去连接某个热点(TKIP+WPA2-PSK),第2次提示到“正在重新对chenj进行验证...”就停止了(如果是正常的过程,应该是重新认证3次然后断开连接吧?)。然后用正确的密码去连接这个热点,也是提示到“正在重新 ...…

查看全部问答∨

分少再加,实际不懂问题求助—PXA270实践

     有几个问题不太理解。        1:我阅读了一个的操作系统(包含驱动程序)的部分代码,发现里面的目录有bsp,也有driver。这两个目录是平行的。 但是我发现在bsp与driver中有重复的内容,其实drive ...…

查看全部问答∨

lwip 建立一个 tcp连接的简要流程

搞了半天也没出来,郁闷死了。。。 哪位能跟我简要说下LWIP 作为客户端,建立一个TCP 连接的简要流程啊,包括都要调用哪几个函数。另外我对各个函数里的callback函数一直没搞明白,比如tcp_connect()里的回调函数。…

查看全部问答∨

请教这个混波电路的原理,谢谢

大家好: 这个电路好像是一个鉴相器,它能够将阻抗 Z 的实部(R)和虚部(Xc)分离出来变成直流电压输出。 以下是我理解的部分: 左上角的 U4C 和 U4D 放大阻抗 Z 两端的电压,输出 A,B 两信号,这是电压向量。 下面 3 级 OP 组成的仪放电路 ...…

查看全部问答∨

spi的sck引脚问题

stm32103VC的spi2的sck为啥没有波形输出,而mosi有波形输出。换了两个片子都这样。郁闷。为啥会这样呢。…

查看全部问答∨

关于ADC0808测量电压并显示

#include<AT89x51.H> #define uchar unsigned char #define uint unsigned int uchar code shuju[]={0xc0,0xf9,0xa4,0xb0, 0x99,0x92,0x82,0xf8, 0x80,0x90};          void  ys(uint a) { uint ...…

查看全部问答∨

生命特征侦测手表

MUC定时采集温度(表皮)、运动传感器(加速度计)信号、采用微型压电陶瓷和橡胶垫采样手腕内侧脉搏振动。数据传输采用314/433M无线芯片+PA放大。显示部分采用SPI接口的OLED显示屏,MCU定时采样数据通过无线芯片发送出去。电池部分用充电锂电池。…

查看全部问答∨
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved