江科协STM32教程:使用串口助手控制LED灯点亮和熄灭(包含全代码过程)
使用USART串口通信,通过上位机串口助手发送关键字符串给STM32执行LED灯点亮熄灭操作的流程。
基本的配置如下所示,GPIO口配置的为PA9推挽输出,用于LED灯的操作。其余注意USART_ITConfig和USART_Cmd开启USART接收中断和使能USART运行。
#include "stm32f10x.h" // Device header
#include <stdio.h>
#include <stdarg.h>
void Serial_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//开启USART1的时钟,USART1总线在APB2上,
//其余的都在APB1上,注意区分
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate=9600;//设置波特率
USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;//硬件流控制
USART_InitStructure.USART_Mode=USART_Mode_Tx|USART_Mode_Rx;//USART模式,发送接收全设置
USART_InitStructure.USART_Parity=USART_Parity_No;//校验位
USART_InitStructure.USART_StopBits=USART_StopBits_1;//停止位
USART_InitStructure.USART_WordLength=USART_WordLength_8b;//字长
USART_Init(USART1,&USART_InitStructure);
USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);//开启串口接收数据中断
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel=USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
NVIC_Init(&NVIC_InitStructure);
USART_Cmd(USART1,ENABLE);
}
接下来要进行发送字符串LED_ON和LED_OFF分别执行点亮和熄灭的操作,比如串口在接受LED_ON这个字符串后,通过程序将接收到的该字符串进行比照,例如使用 strcmp()进行判断,如果接收到的字符串与设置好的字符串相同则执行对应的操作,注意strcmp()包含在#include<string.h>中,需要添加该头文件才能使用。
可以使用数组进行接收字符串,在中断函数里使用状态机的形式进行数据的头尾判断和接收存储。
进入中断后,将串口接收到的字符用一个数组RxData[]暂存,进入if的条件再定义一个RxState 进行判断,初始值赋0,在里面又进行判断接收到的数据是不是用于判断的头字符,定义判断字符为@,同时为了保证数据是重新开始的,加上Serial_RxFlag == 0用且判断,接收到的为@则进入接收数据的部分,注意使用else if判断,里面判断是不是尾字符(用于结束),如果不是的话就进行数据的正式接收,将接收到的字符用数组形式存放在RxData里,然后接收到结束字符后进入最后的收尾工作。
使用"\n"进行判断进入第三步,在里面进行状态重置,记得使用USART_ClearITPendingBit进行标志位清零。状态机部分的代码到此结束。
void USART1_IRQHandler(void)
{
static uint8_t RxState = 0; //定义表示当前状态机状态的静态变量
static uint8_t pRxPacket = 0; //定义表示当前接收数据位置的静态变量
if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET) //判断是否是USART1的接收事件触发的中断
{
uint8_t RxData = USART_ReceiveData(USART1); //读取数据寄存器,存放在接收的数据变量
/*使用状态机的思路,依次处理数据包的不同部分*/
/*当前状态为0,接收数据包包头*/
if (RxState == 0)
{
if (RxData == '@' && Serial_RxFlag == 0) //如果数据确实是包头,并且上一个数据包已处理完毕
{
RxState = 1; //置下一个状态
pRxPacket = 0; //数据包的位置归零
}
}
/*当前状态为1,接收数据包数据,同时判断是否接收到了第一个包尾*/
else if (RxState == 1)
{
if (RxData == '\r') //如果收到第一个包尾
{
RxState = 2; //置下一个状态
}
else //接收到了正常的数据
{
Serial_RxPacket[pRxPacket] = RxData; //将数据存入数据包数组的指定位置
pRxPacket ++; //数据包的位置自增
}
}
/*当前状态为2,接收数据包第二个包尾*/
else if (RxState == 2)
{
if (RxData == '\n') //如果收到第二个包尾
{
RxState = 0; //状态归0
Serial_RxPacket[pRxPacket] = '\0'; //将收到的字符数据包添加一个字符串结束标志
Serial_RxFlag = 1; //接收数据包标志位置1,成功接收一个数据包
}
}
USART_ClearITPendingBit(USART1, USART_IT_RXNE); //清除标志位
}
}
接下来是main函数里的程序代码:
主函数中的LED代码之前的LED代码有介绍这里不再赘述。if用strcmp进行比较,如果相同则进入循环内部执行对应要实现的操作。可以使用Serial_SendString来发送对应反馈信息给串口助手。
#include "stm32f10x.h" // Device header
#include "Serial.h"
#include "LED.h"
#include "string.h"//包含strcmp函数的代码
int main(void)
{
/*模块初始化*/
LED_Init(); //LED初始化
Serial_Init(); //串口初始化
while (1)
{
if (Serial_RxFlag == 1) //如果接收到数据包
{
/*将收到的数据包与预设的指令对比,以此决定将要执行的操作*/
if (strcmp(Serial_RxPacket, "LED_ON") == 0) //如果收到LED_ON指令
{
LED1_ON(); //点亮LED
Serial_SendString("LED_ON_OK\r\n"); //串口回传一个字符串LED_ON_OK
}
else if (strcmp(Serial_RxPacket, "LED_OFF") == 0) //如果收到LED_OFF指令
{
LED1_OFF(); //熄灭LED
Serial_SendString("LED_OFF_OK\r\n"); //串口回传一个字符串LED_OFF_OK
}
else //上述所有条件均不满足,即收到了未知指令
{
Serial_SendString("ERROR_COMMAND\r\n"); //串口回传一个字符串ERROR_COMMAND
}
Serial_RxFlag = 0; //处理完成后,需要将接收数据包标志位清零,否则将无法接收后续数据包
}
}
}
(此时LED灯亮起)
作者:左耳460