⑤串口发送数据

本文详细介绍了如何使用51单片机通过串口发送数据至电脑,并展示了完整的程序代码。文章首先解释了为何使用最小开发板进行实验的重要性,接着指导读者如何正确连接最小开发板,最后提供了详细的51单片机初始化及数据发送函数实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

说明:单片机连接电脑,在串口工具上查看单片机发来的数据。接收数据下一章再教。
原料:最小开发板(晶振为115200),51单片机,usb转ttl

在这里插入图片描述

一、为什么要用最小开发版进行实验?
可能刚开始学单片机的你们,都是人手一个单片机学习板,烧录程序到单片机也是用单片机学习板。单片机最小开发板和单片机学习板的晶振不同(学习板的一般为120000),所以在TX发送数据的时候,会乱码。
记住:用学习板烧录完程序之后,将单片机插到最小开发板上,再连接电脑。

当然也有些同学们会直接用最小开发板来下载程序,那样就更好不过了,可以直接忽略这个问题。

二、最小开发板的连线(提示:单片机的P30和P31引脚分别为RX、TX)

在这里插入图片描述

三、程序
重点:
1在百度上仔细了解单片机初始化
2对指针和数组的了解

#include<reg52.h>
#define uint unsigned int
#define uchar unsigned char

/* 定义I/O口专区  */
sbit led = P0^0;   
/* 定义I/O口专区 结束*/


/*自定义延时函数专区	 开始*/
void delay(int i)
{
while(i--);
}
/*延时函数专区结束*/


/*发送数据专函数区*/
void Send_Uart(uchar value)
{
	SBUF = value;//缓存
	while(TI==0); //每次发送完数据之后TI会自动置1	,即关闭发送功能
	TI = 0;//让TI清零,以便下次送数据
}
/*发送数据专函数区结束*/

/*发送数据函数*/
void send(uchar *puf)
{
	while(*puf != '\0')//指针结束符是\0,当*puf等于\0的时候,说明字符已经输入完成
	{
		Send_Uart(*puf);//每次接受一个字符
		puf++;
	}
	
	delay(1000);//让单片机反应过来
}

/*51单片机初始化*/
void Uart_Init()
{
	TMOD = 0x20;  //定时器1,工作方式2
	PCON = 0x00;  //不加倍率
	SCON = 0x50;  //串口工作方式1
	TH1 = 0xfd;
	TL1 = 0xfd;   //定时器工作方式2可以自重载,这里设置9600波特率
	TR1 = 1;      //启动定时器
	ES = 0;       //打开串口中断
	EA = 1;       //打开总中断 	
}
//一般这个都是配套使用的,要理解的话去百度,仔细了解每个值的意思。
/*51单片机初始化结束*/


void main()//这里弄个小灯闪烁是因为天调试使的时候可以知道代码是否在运行,也可以知道代码在哪一步停止,哪一步出错
{
	Uart_Init();/*51单片机初始化*/
	led = 0;
	send("您好同学们\r\n");// \n是换行
	delay(50000);
	send("欢迎加入佛科院物联网协会\r\n");//哎呀\r忘记是什么意思了。要学会自己百度哦
	led = 1;
	delay(50000);
	led = 0;
	send("你好熟知宇某\r\n");
	delay(50000);
	led = 1;
	

	while(1);
}



四、运行结果

在这里插入图片描述

通过STM32 USART1 完成下列串口通信功能。 串口通信配置:波特率设置为9600bps,8个数据位,1个停止位,无校验。 ① 设置途经地、目的地坐标 通过串口调试工具向设备发送一系列的途经地、目的地坐标,数字以英文逗号 分隔,并用括号包裹。 坐标为整数,X、Y坐标取值范围为0 – 999,坐标轴单位为cm。 举例: 发送: (48,92) 应答: Got it 说明:通过计算机向设备串口发送1组坐标(48,92),若设备处于“空闲”状态, 设备应答Got it, 否则应答Busy。只有一组坐标数据,表示该组数据为目的 地坐标,X坐标为48,Y坐标为92。 举例: 发送: (48,92,90,100,200,3,20,60) 应答: Got it 说明:通过计算机向设备串口发送4组坐标信息,若设备处于“空闲”状态,设 备应答Got it, 否则应答Busy。第一个途经地的X坐标为48,Y坐标为92, 目的地的X坐标为20,Y坐标为60。 ② 删除途经地(路径规划) 通过串口调试工具向设备发送{X,Y},表示删除一个途经地坐标。 举例: 发送: {200,3} 应答: Got it 说明:只要途经地坐标已经设置,且设备尚未经过该途经地点,均可以删除该 途经地坐标。若该途经地不存在或已经失效,返回Nonexistent。 ③ 设置场景 通过串口调试工具向设备发送[1…4],表示配置设备的工作场景。 3 / 8 举例: 发送: [1] 应答: Got it 说明:支持4种工作场景配置,在“运行”状态下,向设备发送[1],表示将设 备的工作场景配置为场景1,其它状态下,设备应答Device offline。 ④ 查询设备状态 通过串口调试工具向设备发送字符?,表示查询设备当前的状态。 举例: 发送: ? 应答: Idle 说明:向设备发送查询设备状态字符?,若设备处于“空闲”状态,设备应答 Idle,处于“等待”状态,设备应答Wait,“运行”状态应答Busy。 ⑤ 查询设备位置 通过串口调试工具向设备发送查询位置字符#,表示查询设备的当前位置。 举例: 发送: # 应答: (9,100) ** 所有串口通信指令和应答内容均为ASCII字符,若设备串口接收到未定义的 指令或错误设置,指令不生效,返回Error。 ** 严格按照上述格式的约定,设计设备的串口通信功能,区分大小写,勿添加 回车、换行等其它内容。
最新发布
03-18
<think>好的,我现在需要帮助用户实现基于STM32 USART1串口通信功能。用户的需求包括配置串口参数,处理多种指令,如设置坐标、删除途经点、切换场景、查询状态和位置,以及处理非法指令。我需要分步骤思考如何解决这个问题。 首先,用户提到了USART1的配置,波特率9600,8数据位,1停止位,无校验。根据引用[1]和[2],USART的配置包括GPIO和USART本身的设置,还需要使能接收中断。我应该先确认如何配置这些参数。引用[2]提到数据位长度可选8或9,这里选8;停止位选1位;校验位选无校验。所以需要配置USART_InitStructure中的相应参数,比如USART_WordLength_8b,USART_StopBits_1,USART_Parity_No。 接下来,初始化GPIO。USART1的TX是PA9,RX是PA10,需要配置为复用推挽输出和浮空输入。这部分需要参考STM32的GPIO配置步骤,使用GPIO_InitTypeDef结构体,设置正确的模式。 然后,使能USART1和接收中断。根据引用[1],需要调用USART_Cmd和USART_ITConfig函数,开启USART1和接收中断。NVIC设置也是必须的,确保中断优先级配置正确。 接下来是中断服务函数的实现。用户需要接收ASCII字符串指令,所以需要在中断服务函数中读取USART_DR寄存器,将接收到的字符存入缓冲区,并检测帧结束符,比如回车换行符。当检测到结束符时,置位标志位,主循环中处理数据。 在主程序中,需要解析接收到的指令。用户提到的功能包括设置目标、删除途经点、切换场景、查询状态和位置。每个指令可能有不同的格式,比如“SET:TARGET,X,Y”,需要解析命令头和参数。这里可能需要使用字符串处理函数如sscanf或者自己编写解析逻辑。 对于删除途经点,用户可能需要发送类似“DEL:ID”的指令,需要从存储结构中查找并删除对应的途经点。可能需要维护一个数组或链表来存储途经点,处理时需要考虑边界情况,比如ID不存在的情况,此时返回错误。 场景切换命令如“MODE:SCENE1”,需要根据不同的场景值改变系统的工作模式,可以通过全局变量来保存当前场景,并在解析命令后更新该变量。 状态和位置查询需要响应“QUERY:STATUS”或“QUERY:POSITION”指令,从系统中获取当前数据并格式化为字符串发送串口。这部分可能需要访问其他模块的数据,比如传感器或GPS模块,假设这些数据已经可以通过特定函数获取。 非法指令处理需要在解析失败时返回“Error”,所以需要在解析函数中检查命令的有效性,如果不符合预定格式,立即返回错误信息。 此外,需要注意数据发送函数。引用[1]提到使用字符发送函数,所以在发送响应时,需要逐个字符发送或使用DMA(如果需要大量数据传输)。但用户的需求中可能数据量不大,直接使用轮询方式发送即可。 测试和调试部分也很重要,需要使用串口调试助手发送各种指令,验证解析是否正确,响应是否符合预期。特别是处理非法指令时,需要覆盖各种可能的错误格式。 可能遇到的问题包括缓冲区溢出,所以需要设置合理的缓冲区大小,并在接收时检查长度。此外,中断服务函数应尽量简短,避免处理复杂逻辑,快速将数据存入缓冲区并交由主循环处理。 最后,代码结构方面,初始化配置放在主函数开始,中断服务函数处理接收,主循环中检查接收完成标志,调用解析函数,执行相应操作并发送响应。需要确保线程安全,比如在访问全局变量时可能需要禁用中断或使用临界区保护。 现在需要将这些思考整理成步骤,并确保代码示例正确,配置参数符合要求,同时处理各种指令的解析和响应。可能还需要考虑如何存储途经点,使用数据结构如数组或链表,并实现删除和添加功能。</think>根据需求,实现STM32 USART1串口通信功能的步骤如下: ### 一、USART1硬件配置(基于标准库) ```c void USART1_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; // 1. 时钟使能 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE); // 2. GPIO配置(PA9-TX,PA10-RX) 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); // 3. USART参数配置 USART_InitStructure.USART_BaudRate = 9600; 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_Tx | USART_Mode_Rx; USART_Init(USART1, &USART_InitStructure); // 4. 中断配置 USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); // 使能接收中断 NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); USART_Cmd(USART1, ENABLE); // 使能USART1 } ``` ### 二、中断服务函数实现 ```c #define RX_BUF_SIZE 128 volatile uint8_t rx_buffer[RX_BUF_SIZE]; volatile uint16_t rx_index = 0; volatile uint8_t rx_flag = 0; void USART1_IRQHandler(void) { if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) { uint8_t ch = USART_ReceiveData(USART1); if(rx_index < RX_BUF_SIZE-1) { rx_buffer[rx_index++] = ch; // 检测帧结束符(假设以\r\n结尾) if(ch == '\n' && rx_buffer[rx_index-2] == '\r') { rx_buffer[rx_index] = '\0'; // 添加字符串终止符 rx_flag = 1; } } else { rx_index = 0; // 防止缓冲区溢出 } } } ``` ### 三、主程序逻辑框架 ```c typedef struct { float x; float y; } Coordinate; Coordinate targets[10]; // 目标点存储 Coordinate waypoints[50]; // 途经点存储 uint8_t scene_mode = 0; // 场景模式 void ProcessCommand(char* cmd) { // 示例指令解析逻辑 if(strncmp(cmd, "SET:TARGET,", 11) == 0) { float x, y; if(sscanf(cmd+11, "%f,%f", &x, &y) == 2) { // 存储目标点 USART_SendString("OK: Target set\r\n"); } else { USART_SendString("ERROR: Invalid format\r\n"); } } // 其他指令处理... } int main(void) { USART1_Config(); while(1) { if(rx_flag) { ProcessCommand((char*)rx_buffer); rx_index = 0; rx_flag = 0; } // 其他任务... } } ``` ### 四、关键功能实现要点 1. **坐标设置解析**: - 使用`sscanf`解析形如`SET:TARGET,12.34,56.78\r\n`的指令 - 验证数值范围有效性(如经纬度范围) 2. **途经点删除**: ```c void DeleteWaypoint(int id) { if(id >=0 && id < MAX_WAYPOINTS) { waypoints[id].x = -1; // 标记为无效 USART_SendString("OK: Deleted\r\n"); } else { USART_SendString("ERROR: Invalid ID\r\n"); } } ``` 3. **场景切换**: ```c void SetSceneMode(uint8_t mode) { if(mode <= MAX_SCENE_MODE) { scene_mode = mode; USART_SendString("OK: Mode changed\r\n"); } else { USART_SendString("ERROR: Invalid mode\r\n"); } } ``` 4. **状态查询响应**: ```c void SendStatus(void) { char buf[64]; sprintf(buf, "STATUS: Mode=%d, Targets=%d\r\n", scene_mode, CountValidPoints(targets)); USART_SendString(buf); } ``` ### 、协议设计建议 1. **指令格式**: ``` [命令类型]:[参数1],[参数2]\r\n ``` 示例: - 设置目标:`SET:TARGET,116.3974,39.9093\r\n` - 删除途经点:`DEL:WP,5\r\n` - 查询位置:`QUERY:LOC\r\n` 2. **错误处理机制**: - 添加CRC校验(可选) - 超时重传机制 - 错误计数器防死锁 [^1]: USART初始化配置参考 [^2]: 串口协议参数配置说明
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值