串口通信——stm32F407实现串口发送坐标,输出x坐标和y坐标

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. 实验结果

如下图所示:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4. 总结

在数据的类型上,x和y的坐标值类型是 int16_t ,就是有正负号,写程序是开始写成uint16_t,导致输出负数错误。

  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值