1. 实验目的
通过串口助手发送一个(a,b),需要输出x = a,y = b;
2. 实验准备和流程
初始化串口;
编写接收数据中断函数;
编写转换函数;
编写main函数。
2.1 初始化串口
//配置中断函数,这个函数下面有调用
void EXTI_NVIC_Config(void){
//NVIC初始化结构体
NVIC_InitTypeDef NVIC_InitStruct;
//设置中断优先级的分组
//就是设置主抢占优先级和子抢占优先级各是几,这里是分组为1,代表主优先级可以是0和1(就是1个位来设置主优先级),子优先级是0-7,是2的3次方
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
//配置USART为中断源
NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn;
//配置抢占优先级
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
//配置子优先级
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
//使能中断
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);
}
//串口初始化函数
void USART_Config(void){
//1.初始化GPIO(PA9(接串口1的TX引脚),这里是PA10(接串口1的RX引脚))
//初始化结构体 GPIO_InitStruct
//里面是GPIO的速度,上下拉,输出类型等
GPIO_InitTypeDef GPIO_InitStruct;
//USART结构体
USART_InitTypeDef USART_InitStruct;
//打开GPIOA时钟(一般开时钟要放到前面的位置,然后再是设置上拉,输出这些)
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE); //使能时钟必须放到前面,不然后面的操作不会使灯点亮
//打开USART1时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//使能USART1时钟
//复位串口1
GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1); //PA9 复用为 USART1
GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1); //PA10 复用为 USART1
//驱动是哪个引脚 PA9/PA10
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9|GPIO_Pin_10;
//模式是复用功能
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
//输出的速度
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
//推挽复用输出
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
//上拉
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
//变量获取它的指针,取地址就行(&)
GPIO_Init(GPIOA,&GPIO_InitStruct);
//2.初始化串口
//使能串口时钟 (放在最上面了)
//配置波特率
USART_InitStruct.USART_BaudRate = 115200; //设置波特率115200
//配置针数据字长
USART_InitStruct.USART_WordLength = USART_WordLength_8b; //字长为8位数据格式
//配置停止位
USART_InitStruct.USART_StopBits = USART_StopBits_1; //设置为一个停止位
//配置校验位
USART_InitStruct.USART_Parity = USART_Parity_No; //无奇偶校验位
//配置硬件流控制
USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //不使用硬件流控制
//配置工作模式
USART_InitStruct.USART_Mode = USART_Mode_Rx|USART_Mode_Tx; //收发模式
//完成串口的初始化配置
USART_Init(USART1,&USART_InitStruct);
//串口中断优先级配置(初始化)
EXTI_NVIC_Config();
//使能串口接收中断(中断配置函数) 这是使能哪种中断,比如在接收到数据的时候(RXNE 读数据寄存器非空),我们要产生中断
USART_ITConfig(USART1,USART_IT_RXNE,ENABLE); //生成串口中断 接收到数据就产生了中断
USART_ITConfig(USART1, USART_IT_IDLE, ENABLE); // 开启空闲中断
//使能串口(串口使能函数)
USART_Cmd(USART1,ENABLE);
}
2.2 编写接收数据中断函数
typedef struct {
char USART1_RX_BUF[320]; //声明一个缓冲数组
uint16_t USART1_RX_BUF_length; //记录缓存数组的长度
uint16_t comma_Index; //记录逗号的索引
uint16_t Data_flag; //接收完数据的标志
int16_t cnt; //数组的索引值
int16_t x_value; // x坐标值, 这里定义要有符号
int16_t y_value; // y坐标值, 这里定义要有符号
} UsartTypeDef; //串口结构体
//接收数据中断函数
void USART1_IRQHandler(void) {
//当 RDR 移位寄存器的内容已传输到 USART_DR 寄存器时,该位由硬件置 1。代表数据接收完成
if (USART_GetITStatus(USART1, USART_IT_RXNE)) { //接收到数据了
UsartStructure.USART1_RX_BUF[UsartStructure.cnt] = USART_ReceiveData(USART1);
if (UsartStructure.USART1_RX_BUF[UsartStructure.cnt] == 0x29) { //判断是否接收到右括号,也就是右括号代表着接收结束,这里也可以写 == ")"
UsartStructure.USART1_RX_BUF_length = UsartStructure.cnt; //记录串口缓存数组长度
UsartStructure.cnt = 0; //缓存数组索引置为0
UsartStructure.Data_flag = 1;
} else {
UsartStructure.cnt++;
}
if (UsartStructure.cnt >= 320 || !(UsartStructure.USART1_RX_BUF[0] == 0X28)) { //接收数据异常,初始化数组,第一个接收到左半边括号
UsartStructure.cnt = 0;
}
}
}
2.3 编写转换函数
char ASCII_To_Value(char asc) { //ASCII转换成数字的函数
char value;
switch (asc){
case 0x30: //0的ASC码时0x30,十进制48
value = 0;
break;
case 0x31:
value = 1;
break;
case 0x32:
value = 2;
break;
case 0x33:
value = 3;
break;
case 0x34:
value = 4;
break;
case 0x35:
value = 5;
break;
case 0x36:
value = 6;
break;
case 0x37:
value = 7;
break;
case 0x38:
value = 8;
break;
case 0x39:
value = 9;
break;
}
return value;
}
void receive_coordinate(char *array) {
uint16_t i = 0;
int16_t x_value = 0;
int16_t y_value = 0;
for (i = 0; i < UsartStructure.USART1_RX_BUF_length; i++) {
if (array[i] == 0X2C) { //检测英文逗号
UsartStructure.comma_Index = i;
}
}
if (array[1] == 0X2D) { //判断是负号
for (i = 2; i < UsartStructure.comma_Index; i++) {
x_value += ASCII_To_Value(array[i]) * pow(10, UsartStructure.comma_Index - i - 1); //转换成数字
}
UsartStructure.x_value = -x_value;
} else { //不为负号
for (i = 1; i < UsartStructure.comma_Index; i++) {
x_value += ASCII_To_Value(array[i]) * pow(10, UsartStructure.comma_Index - i - 1); //转换成数字
}
UsartStructure.x_value = x_value;
}
if (array[UsartStructure.comma_Index + 1] == 0X2D) { //判断逗号后一个的是否为负数
for (i = UsartStructure.comma_Index + 2; i < UsartStructure.USART1_RX_BUF_length; i++) {
y_value += ASCII_To_Value(array[i]) * pow(10, UsartStructure.USART1_RX_BUF_length - i - 1); //转换成数字
}
UsartStructure.y_value = -y_value;
} else {
for (i = UsartStructure.comma_Index + 1; i < UsartStructure.USART1_RX_BUF_length; i++) {
y_value += ASCII_To_Value(array[i]) * pow(10, UsartStructure.USART1_RX_BUF_length - i - 1); //转换成数字
}
UsartStructure.y_value = y_value;
}
}
2.4 main.c函数
int main(void) {
delay_init(168); //初始化延时函数
USART_Config();
while (1) {
if (UsartStructure.Data_flag == 1) {
receive_coordinate(UsartStructure.USART1_RX_BUF); //传入数组
UsartStructure.Data_flag = 0; //数据接收标志位置为0
printf("x_value = %d\r\n", UsartStructure.x_value);
printf("y_value = %d\r\n", UsartStructure.y_value);
}
}
}
3. 实验结果
如下图所示:
文章来源:https://www.toymoban.com/news/detail-626261.html
4. 总结
在数据的类型上,x和y的坐标值类型是 int16_t ,就是有正负号,写程序是开始写成uint16_t,导致输出负数错误。文章来源地址https://www.toymoban.com/news/detail-626261.html
到了这里,关于串口通信——stm32F407实现串口发送坐标,输出x坐标和y坐标的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!