STM32F10x串口通信控制LED不同模式以及亮灭
非常简单!具体功能如下:
- 默认状态:key0->绿灯翻转 key1->红灯翻转
- 串口输入1:key0->红灯翻转 key1->绿灯翻转
- 串口输入2:key0->全灯灭 key1->全灯灭
- 串口输入3:测试用——> 红灯翻转
- 串口输入4:测试用——> 绿灯翻转
- 串口输入5:led流水灯
鉴于大部分同学是为了快速入门或者完成作业,本次教程非常无脑化,并且实时更新。
首先具备如下:
请确保CH340驱动正常运作,有无正常运转点击我的电脑 ——>管理——>查看端口
我的常见错误是win10不允许驱动签名,这时候百度一下使用高级重启重新配置一下就行。
1.软件
1.XCOM V2.0(ALIENTEK官方推荐)
2. Keil5 编译软件
2.硬件
1.STM32F103正点原子精英版
3.代码来源
1.正点原子实验三按键输入实验
2.正点原子实验四串口通信实验
4.代码源码
4.1main.c文件
#include "led.h"
#include "delay.h"
#include "key.h"
#include "sys.h"
#include "usart.h"
extern u8 mod ;
int main(void)
{
vu8 key=0;
mod = 0;
KEY_Init();
delay_init(); //延时函数初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
uart_init(115200); //串口初始化为115200
LED_Init(); //LED端口初始化
KEY_Init(); //初始化与按键连接的硬件接口
USART_SendString(USART1, "一次非常可爱的串口实验\r\n"); //发送字符串
USART_ClearFlag(USART1,USART_FLAG_RXNE); //接收前先清空标志位
while(1)
{
key=KEY_Scan(0);
if(key)
{
switch(key)
{
case KEY1_PRES: //默认控制状态
LED1=!LED1; //key0红灯亮 key1绿灯亮
break;
case KEY0_PRES:
LED0=!LED0;
break;
}
}else delay_ms(10);
/*************************key0绿灯亮 key1红灯亮********************************/
if(mod == 1)
{
USART_SendString(USART1, "控制模式1\r\n");
LED1=1;
LED0=1;
while(1)
{
key=KEY_Scan(0);
if(key)
{
switch(key)
{
case KEY1_PRES:
LED0=!LED0;
break;
case KEY0_PRES:
LED1=!LED1;
break;
}
}else delay_ms(10);
}
}
/*******************同时亮灭*********************/
if(mod == 2)
{
USART_SendString(USART1, "控制模式2\r\n"); //发送字符串
LED1=1;
LED0=1;
while(1)
{
key=KEY_Scan(0);
if(key)
{
switch(key)
{
case KEY1_PRES:
LED1=1;
LED0=1;
break;
case KEY0_PRES:
LED1=0;
LED0=0;
break;
}
}else delay_ms(10);
}
}
/**************流水灯*********************/
if(mod == 5)
{
USART_SendString(USART1, "控制模式3\r\n"); //发送字符串
delay_ms(500);
LED1=0;
LED0=1;
while(1)
{
LED1=!LED1;
LED0=!LED0;
delay_ms(1000);
}
}
delay_ms(10);
}
}
4.2usart.c文件
#include "sys.h"
#include "usart.h"
#include "led.h"
u8 mod = 0;
#if SYSTEM_SUPPORT_OS
#include "includes.h"
#endif
#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
#if EN_USART1_RX //如果使能了接收
//串口1中断服务程序
//注意,读取USARTx->SR能避免莫名其妙的错误
u8 USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.
u16 USART_RX_STA=0; //接收状态标记
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
}
void USART_SendString(USART_TypeDef* USARTx, char *DataString)
{
int i = 0;
USART_ClearFlag(USARTx,USART_FLAG_TC); //发送字符前清空标志位(否则缺失字符串的第一个字符)
while(DataString[i] != '\0') //字符串结束符
{
USART_SendData(USARTx,DataString[i]); //每次发送字符串的一个字符
while(USART_GetFlagStatus(USARTx,USART_FLAG_TC) == 0); //等待数据发送成功
USART_ClearFlag(USARTx,USART_FLAG_TC); //发送字符后清空标志位
i++;
}
}
void USART1_IRQHandler(void) //串口中断执行函数
{
char USART1_ReceiveData = 0; //接收PC端发送过来的字符
if(USART_GetFlagStatus(USART1,USART_IT_RXNE) == 1) //USART_FLAG_RXNE判断数据,== 1则有数据
{
USART1_ReceiveData = USART_ReceiveData(USART1); //通过USART1串口接收字符
USART_ClearFlag(USART1,USART_IT_RXNE); //接收后先清空标志位
}
if( '1' == USART1_ReceiveData ) //如果数据为1,LED1灯电平翻转
{
LED0 = !LED0;
mod = 1 ;
}
if( '2' == USART1_ReceiveData ) //如果数据为2,LED2灯电平翻转
{
LED1= !LED1;
mod = 2 ;
}
if( '3' == USART1_ReceiveData ) //如果数据为1,LED1灯电平翻转
{
LED0 = !LED0;
}
if( '4' == USART1_ReceiveData ) //如果数据为2,LED2灯电平翻转
{LED1= !LED1;}
if( '5' == USART1_ReceiveData ) //如果数据为2,LED2灯电平翻转
{mod = 5 ;}
}
#endif
以上便是实现功能的两个主要代码文件
原理很简单有基础的同学一眼能看明白,没基础的同学直接复制就行。
检查文件是否有缺,key.c文件和led.c针对不同单片机可以单独配置,此时无需更改。
5.最后
波特率为115200,
打开串口,若屏幕显示:开头图片,则程序正常运行。
*随便一小时写的程序,简陋实用,大佬请见笑,写给需要的同学,学linux去啦!!。。。*
链接:https://pan.baidu.com/s/1pO2wB9TDxed4JPzp04XBlg
提取码:ibhm
附上程序源码:
https://download.csdn.net/download/m0_50629392/54221946?spm=1001.2014.3001.5501