历史上的今天
返回首页

历史上的今天

今天是:2025年03月09日(星期日)

正在发生

2019年03月09日 | STM32串口通信之超级终端控制LED灯

2019-03-09 来源:eefocus

一、硬件介绍


本程序使用开发板:STM32-PZ6806L


1、GPIO控制LED


开发板中LED的硬件电路参看:直接通过寄存器地址操作控制LED灯


2、串口


开发板中连接了MCU的2个串口,分别为USART1和USART3,其中USART1通过CH340G接PC端USB口,实现USB转串口功能,可以用于程序下载和串口通信,但通过PC端的超级终端连接时不能连接,所以本程序使用开发板上的另一个串口USART3,该串口信号转换成RS232,通过直连串口线与PC端的COM口相连,可以实现与超级终端通信。


开发板串口的硬件连接图请参考:STM32串口通信之Hello


二、项目创建与配置


请参看《STM32串口通信之Hello》中的“使用库函数的串口程序项目配置”,在此基础上,在"User"文件夹下新建"Led"文件夹,并将该文件夹配置在"C/C++"选项卡中的"Include Paths"包含文件路径中。


三、LED灯控制


1、新建"Led.h"文件并保存在"User/Led"文件夹下,内容如下:


#ifndef __LED__H


#define __LED__H


#include "stm32f10x.h"


#define LED_PORT     GPIOC


#define LED_PIN        (GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7)


#define LED_PORT_RCC RCC_APB2Periph_GPIOC


#define LED1 GPIO_Pin_0


#define LED2 GPIO_Pin_1


#define LED3 GPIO_Pin_2


#define LED4 GPIO_Pin_3


#define LED5 GPIO_Pin_4


#define LED6 GPIO_Pin_5


#define LED7 GPIO_Pin_6


#define LED8 GPIO_Pin_7


 


void LED_Init(void);


void LED_On(u8 x, u8 en);


#endif


2、新建"Led.c"文件并保存在"User/Led"文件夹下,内容如下:


#include "led.h"


void LED_Init()


{


         GPIO_InitTypeDef GPIOC_0_mode;


         RCC_APB2PeriphClockCmd( LED_PORT_RCC, ENABLE );           //使能GPIOC时钟


         GPIOC_0_mode.GPIO_Pin = LED_PIN;


         GPIOC_0_mode.GPIO_Speed = GPIO_Speed_50MHz;


         GPIOC_0_mode.GPIO_Mode = GPIO_Mode_Out_PP;


         GPIO_Init(GPIOC, &GPIOC_0_mode);


}


void LED_On(u8 x, u8 en)


{


         uint16_t led[] = {LED1,LED2,LED3,LED4,LED5,LED6,LED7,LED8};


         if(x


                   return;


         if(en=='y')


                   GPIO_ResetBits(LED_PORT,led[x-0x31]);


         else


                   GPIO_SetBits(LED_PORT,led[x-0x31]);


}


LED_Init函数使能GPIOC时钟,设置GPIOC_0~GPIOC_7为推挽输出模式,LED_On函数根据参数x和en来设置单个LED灯的亮灭状态,调用函数GPIO_ResetBits来复位管脚,即点亮LED灯,调用函数GPIO_SetBits来置位管脚,即灭LED灯。x参数为第几个LED灯的数字字符,en参数为'y'字符或'n'字符,'y'表示点亮,'n'表示灭灯。


四、串口通信程序


该串口通信采用USART3,发送数据采用查询方式,接收数据采用中断方式,所以需要使能GPIOB和USART3时钟、配置中断、配置USART3、使能中断和使能USART3等操作。


1、创建"usrt.h"文件并保存在"User/Uart"文件夹下,内容为:


#ifndef __UART__H


#define __UART__H


#include "stm32f10x.h"


#include "stdarg.h"


#include "stdlib.h"


#include "string.h"


#include "stdio.h"        


#define EN_USART1 0         //禁用USART1


#define EN_USART3 1         //启用USART3


 


#define USART_n                 USART3    //使用USART3用于fputc


 


#define USART1_REC_LEN                          200 


extern u8  USART1_RX_BUF[USART1_REC_LEN];


extern u16 USART1_RX_STA;  


 


#define USART3_REC_LEN                          200 


extern u8  USART3_RX_BUF[USART3_REC_LEN];


extern u16 USART3_RX_STA;  


 


void USART1_Config(u32 baud);


void USART1_printf(char* fmt,...);


 


void USART3_Config(u32 baud);


void USART3_printf(char* fmt,...);


#endif


2、创建"usrt.c"文件并保存在"User/Uart"文件夹下,内容为:


#include "uart.h"


 


//重写fputc函数


int fputc(int ch, FILE *f){      


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


  USART_SendData(USART_n, (unsigned char)ch);     


         return ch;


}


 


#if EN_USART1


u8 USART1_RX_BUF[USART1_REC_LEN];     //接收缓冲区,最大USART_REC_LEN个字节.


//接收标志


//bit15,        置位表示接受完成


//bit14,        置位表示接收到0x0d


//bit13~0,   接收字符个数


u16 USART1_RX_STA=0;       //16位接收记录标志全局变量 


void USART1_Config(u32 baud)


{


         GPIO_InitTypeDef GPIO_InitStructure;


         USART_InitTypeDef USART_InitStructure;


         NVIC_InitTypeDef NVIC_InitStructure;


         //Enable GPIOA and USART1


         RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);


         //Config GPIOA_9 and GPIOA_10


         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;


         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;


         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;


         GPIO_Init(GPIOA, &GPIO_InitStructure);


        


         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;


         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;


         GPIO_Init(GPIOA, &GPIO_InitStructure);


         //USART1 NVIC config


         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);      //配置NVIC中断分组2:2位抢占,2位响应


         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);          //初始化NVIC寄存器


         //Config USART1


         USART_InitStructure.USART_BaudRate = baud;


         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_ITConfig(USART1, USART_IT_RXNE, ENABLE);//使能USART1的接收中断


         //Enable USART1


         USART_Cmd(USART1, ENABLE);


}


 


void USART1_IRQHandler(void){ //USART1中断函数 


         u8 Res;


         //(USART1_RX_STA&0x3FFF)为数据的长度(不包括回车符)


         //当(USART1_RX_STA&0xC000)为真时表示数据接收完成(超级终端按下回车键),


         //读到0x0d 0x0a表示数据结束


         //在main函数中处理完接收数据后将USART_RX_STA置0


                   printf("a");


         if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)


         {    


                   Res =USART_ReceiveData(USART1);//接收一个字符


                   printf("%c",Res); //会送给PC


                   if((USART1_RX_STA & 0x8000)==0)            //本次接收未完成


                   {                                  


                            if(USART1_RX_STA & 0x4000)                     //已经接收到了0x0d


                            {                                                              


                                     if(Res!=0x0a)      //如果已经接收了回车符,而本次接收的不是换行符,则数据出错


                                               USART1_RX_STA = 0;       


                                     else


                                               USART1_RX_STA |= 0x8000;      //标记数据接收完成


                            }


                            else   //没有接收过0X0D表示为信息字符


                            {                                 


                                     if(Res==0x0d)    //本次接收是0x0d,则在USART1_RX_STA中标记


                                               USART1_RX_STA |= 0x4000;


                                     else   //本次接收不是0x0d,则确定是信息字符,存入数组中


                                     {


                                               USART1_RX_BUF[USART1_RX_STA & 0X3FFF]=Res ; //字符存入数组中


                                               USART1_RX_STA++;         //数据长度加1


                                               if(USART1_RX_STA > (USART1_REC_LEN-1))   //如果数据长度超过缓冲区大小,出错,重新接收


                                                        USART1_RX_STA=0;


                                     }                


                            }


                   }               


         }


}


#endif


 


#if EN_USART3


u8 USART3_RX_BUF[USART3_REC_LEN];     //接收缓冲区,最大USART_REC_LEN个字节.


//接收标志


//bit15,        置位表示接受完成


//bit14,        置位表示接收到0x0d


//bit13~0,   接收字符个数


u16 USART3_RX_STA=0;       //16位接收记录标志全局变量 


void USART3_Config(u32 baud)   //初始化UASRT3


{


  //GPIO端口设置


  GPIO_InitTypeDef GPIO_InitStructure;


         USART_InitTypeDef USART_InitStructure;


         NVIC_InitTypeDef NVIC_InitStructure;


                    


         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB , ENABLE); //使能UART3对应的GPIOB


         RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE); //使能串口的RCC时钟


 


         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11; //配置USART3的RX引脚PB11


         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入


         GPIO_Init(GPIOB, &GPIO_InitStructure);


 


         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //配置USART3的TX引脚PB10


         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;


         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;         //服用推挽输出


         GPIO_Init(GPIOB, &GPIO_InitStructure); 


 


   //Usart3 NVIC 配置


         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);


  NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;


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


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


         NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                            //IRQ通道使能


         NVIC_Init(&NVIC_InitStructure);          //初始化NVIC


   //USART3 初始化设置


         USART_InitStructure.USART_BaudRate = baud;//波特率;


         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(USART3, &USART_InitStructure); //初始化串口


         USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);//使能接收中断


         USART_Cmd(USART3, ENABLE);                    //使能串口


}


 


void USART3_IRQHandler(void)  //USART3中断函数


{     


         //(USART1_RX_STA&0x3FFF)为数据的长度(不包括回车符)


         //当(USART1_RX_STA&0xC000)为真时表示数据接收完成(超级终端按下回车键),


         //读到0x0d 0x0a表示数据结束


         //在main函数中处理完接收数据后将USART_RX_STA置0


         u8 Res;


         //       printf("a");


         if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET)


         {    


                   Res =USART_ReceiveData(USART3);//接收一个字符


                   printf("%c",Res); //回送给PC


                   if((USART3_RX_STA & 0x8000)==0)            //本次接收未完成


                   {                                  


                            if(USART3_RX_STA & 0x4000)                     //已经接收到了0x0d


                            {                                                              


                                     if(Res!=0x0a)      //如果已经接收了回车符,而本次接收的不是换行符,则数据出错


                                               USART3_RX_STA = 0;       


                                     else


                                               USART3_RX_STA |= 0x8000;      //标记数据接收完成


                            }


                            else   //没有接收过0X0D表示为信息字符


                            {                                 


                                     if(Res==0x0d)    //本次接收是0x0d,则在USART1_RX_STA中标记


                                               USART3_RX_STA |= 0x4000;


                                     else   //本次接收不是0x0d,则确定是信息字符,存入数组中


                                     {


                                               USART3_RX_BUF[USART3_RX_STA & 0X3FFF]=Res ; //字符存入数组中


                                               USART3_RX_STA++;         //数据长度加1


                                               if(USART3_RX_STA > (USART3_REC_LEN-1))   //如果数据长度超过缓冲区大小,出错,重新接收


                                                        USART3_RX_STA=0;


                                     }                


                            }


                   }               


         }


}


#endif


3、"main.c"程序


#include "uart.h"


#include "led.h"


int main()


{


         u8 ch1, ch2, i;


         LED_Init();//LED GPIO初始配置


         USART3_Config(115200); //USART1配置,接收中断


         USART3_RX_STA = 0xC000; //数据初始为接收回车状态


         for(i=0;i<8;i++)  //将8个LED初始设为灭灯状态


                   LED_On(i+0x31,'n');


         while(1)


         {


                   if(USART3_RX_STA & 0xC000)//接收到回车-0xC000


                   {


                            if((USART3_RX_STA & 0x3FFF)==0) //数据长度为0,显示菜单


                            {


                                     printf("\033[1;47;33m\r\n"); //设置超级终端文字颜色


                                     printf(" xy--开LEDx灯     xn--灭LEDx灯 \r\n");


                                     printf(" 请输入控制指令,按回车键执行! \033[0m\r\n");


                            }


                            else if((USART3_RX_STA&0x3FFF)==2)


                            {


                                     ch1 = USART3_RX_BUF[0];


                                     ch2 = USART3_RX_BUF[1];


                                     if(      ch1>='1' && ch1<='8'&&( ch2=='y' || ch2=='n'))


                                     {


                                               LED_On(ch1, ch2);


                                               printf("LED%c%s\r\n",ch1,ch2=='y'?"开了":"关了");


                                     }


                                     else


                                               printf("命令错误\r\n");


                            }


                            USART3_RX_STA = 0; //完成一次操作,复位


                   }


         }


}


在此程序中分别对USART1和USART3实现了同样的操作,这里实际用到的是USART3,本程序参考杜洋老师的程序实现。


五、项目编译、开发板设置及程序运行


1、在项目的"User"组中加入"led.c"和"uart.c"文件,编译,连接生成.hex文件;


2、将开发板中的P232的两个跳线帽连接到COM3;


3、将程序下载到开发板;


4、在PC机上运行"HyperTerminal"程序,新建连接:


HyperTerminal运行如下:

超级终端上的显示与开发板上LED灯的状态一致。


推荐阅读

史海拾趣

HCC Industries公司的发展小趣事

2015年,HCC Industries迎来了其发展历程中的一个重要转折点。在这一年,公司成功收购了另一家具有强大研发实力和市场份额的微电子企业。此次并购不仅使HCC在技术上得到了进一步的补充和提升,还大大增强了其生产能力和市场覆盖范围。通过整合双方资源,HCC在短时间内实现了规模的快速扩张和效益的显著提升,进一步巩固了其在行业内的领先地位。

Hendon Semiconductors公司的发展小趣事

Hendon Semiconductors在能源管理和照明控制领域也有着显著的成就。公司开发了一系列高效、可靠的能源管理解决方案和照明控制产品,广泛应用于智能家居、商业建筑和工业自动化等领域。这些解决方案不仅帮助客户降低了能耗和运营成本,还提高了能源使用效率和环境可持续性。通过不断创新和优化产品设计,Hendon Semiconductors在能源管理和照明控制市场上赢得了广泛的认可。

振宝佳(DMBJ)公司的发展小趣事

随着电子产业的不断发展,SMT贴片技术逐渐成为电子信息产业的支柱技术之一。振宝佳公司紧跟时代步伐,在网络、通信、军事、工业控制以及汽车电子、家电等所有电子领域里全部采用了SMT贴片技术。这一技术的应用不仅提高了产品的集成度和可靠性,也为客户提供了更加优质的产品和服务。

C-MAC Automotive公司的发展小趣事

在电子行业的早期,C-MAC Automotive公司还是一家名不见经传的小企业。然而,随着电动汽车市场的兴起,公司敏锐地捕捉到了市场机遇。通过投入大量研发资源,C-MAC成功开发出一款高效稳定的电池管理系统,这一技术突破为公司的快速发展奠定了坚实基础。随着产品逐渐获得市场认可,C-MAC的订单量大幅增加,公司规模迅速扩大。

Box Enclosures公司的发展小趣事

随着国内市场的逐渐饱和,Box Enclosures公司决定将目光投向海外市场。公司制定了一系列国际化战略,包括参加国际电子展会、建立海外销售网络等。经过几年的努力,Box Enclosures的产品逐渐打入国际市场,赢得了众多海外客户的青睐。这一国际化战略为公司带来了更广阔的发展空间。

CTC Coils Ltd公司的发展小趣事

面对日益严峻的环境问题,CTC Coils Ltd公司积极响应国家绿色发展的号召,开始实施绿色环保战略。公司引进先进的生产设备和工艺,优化生产流程,减少能源消耗和废物排放。同时,公司还研发出了一系列环保型电感线圈产品,满足了市场对绿色电子产品的需求。

问答坊 | AI 解惑

IP核互连策略及规范

随着超深亚微米工艺的发展, IC设计能力与工艺能力极大提高,采用SoC(System on Chip)将微处理器、IP核、存储器及各种接口集成在单一芯片上,已成为目前IC设计及嵌入式系统发展的趋势和主流。为减少设计风险、缩短设计周期、更集中于应用实现,设 ...…

查看全部问答>

哪位大侠给小弟赐个招吧。

小弟一心想学嵌入式,前天定了块学习板,板子到手了,却不懂的怎么最基本的使用和入门,望各位大侠大哥大姐们帮帮忙,赐个招吧,小弟感激不进。…

查看全部问答>

WINCE5.0支持访问ASP的网站么?

WINCE5.0能访问ASP的网站么??如果可以..服务器端应该用SQL SERVER还是SQL CE 5.0?我只是需要CE能访问PC服务器上面的ASP.提交一些例如修改密码,之类的请求…

查看全部问答>

U_boot1.1.6 编译出错,很郁闷

我用的是arm-linux-gcc-3.3.2   系统fedora 错误如下 t not recognized: failed to merge target specific data of file /usr/local/arm/3.3.2/lib/gcc-lib/arm-linux/3.3.2/libgcc.a(_udivdi3.oS) /usr/local/arm/3.3.2/bin/arm-linux ...…

查看全部问答>

如何在视频窗口里添加图标(图象)

做一个手机上的camera全屏预览的应用程序,要求在全屏预览的窗口上有几个图标来控制拍照和录像。不知咋整,哪位高手支下招,谢谢! ps:在video render前加一个混合两者的filter是可以的,比较麻烦。…

查看全部问答>

谁有ARM开发板卖啊?

我现在在进行嵌入式系统的学习 要用到ARM开发板,但是我是菜鸟 我想买一个ARM开发板,条件如下: 1:价格不要太贵 2:可以是公司或者个人,但是售后一定要有技术支持和配套资料,没有技术支持的等于白买。 3:可以是二手的,同样要有技术支持 ...…

查看全部问答>

数字钟的设计(加急!!!!!)请大牛伸出援手(初学的确需要帮助)

要求用基本逻辑门及74系列中规模芯片实现能显示时分秒和有校正功能的数字钟! 1 请给出完整的几个大模块及其实现的功能,及所选主要器材(我没有完整的设计思路,还请大家帮忙) 2 请写出更为具体的设计方法(至少给点点播也好),初学者真的很不容易. 3 ...…

查看全部问答>

按各厂家提供的PDF文档,列出几种CortexM3、M0的功耗,供参考

按照各厂家提供的PDF文档,列出几种CortexM3、M0的功耗,备参考 …

查看全部问答>

智能U盘相机

  数据卡是数码相机必不可少的影像存储设备,但是它还需要通过各种接入设备的桥接,才能将影像资料导入电脑,再将其分发给所需人群。如此一来,只要有聚会、派对,结束之后,各种影像资料的交流、传输往往会把人弄得焦头烂额。而设计师们则 ...…

查看全部问答>

为stm32f的CRC32申冤---它是主流

哈哈~~~为版主申冤~~~ stm32f的CRC32主流化crc32_mpeg2 多项式: 左移CRC32=X32+X26+X23+X22+X16+X12+X11+X10+X8+X7+X5+X4+X2+X+1 简写:CRCL32_04C11DB7_FFFFFFFF_00000000 最新版V4.08: http://www.hotpower.org/HotAjax/HotPow ...…

查看全部问答>