加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
Car.org 24.10 KB
一键复制 编辑 原始数据 按行查看 历史

小车循迹

分析路径

使用到的函数

void Path_Analysis(char *path, uint8_t mode);
uint8_t Quick_reading_FS(uint8_t linked_list);

路径存放在一个char 数组

char path1[] = {"B7,B6,B4,B2,D2,F2,F4,F6,D2,B6,B7"};
//路径保存变量,在此更新任务路径,路径点需为地图中连续的点,用英文逗号隔开

路径存放

   Path_Analysis(path1, 0);

  /*函数名称:Path_Analysis
	输入参数:path ,mode ,dir_bef(*path 任务路径指针,mode模式<0,1> 开始方向)
					*path为传入的循迹坐标
					mode=0:为有任务循迹模式
					mode=1:无任务循迹模式
	返回参数:空
	说明:通过选择模式来现在是否做任务*/
	void Path_Analysis(char *path, uint8_t mode);
	char *p = path;

	uint8_t check_mode = 0;	 // 循迹模式
	check_mode = mode;
	
	uint8_t Special_Tpg_Flag; //特殊地形标准位

  typedef struct
  {
  	char Cd_X; // 坐标的字母
  	char Cd_Y; // 坐标的数字
  	int k;     // 任务的序号
  	int vernier; // 下一个坐标
  } Statick[50];
  static int linked_list = 0; // 结点编号
  Statick link;
  //路径读取到坐标数组中
  do
  {
  	link[linked_list].Cd_X = *p;
  	link[linked_list].Cd_Y = *(p + 1);
  	link[linked_list].k = linked_list;
  	link[linked_list].vernier = linked_list + 1;
  	linked_list++;
  	p = p + 3;

      /*
      linked_list = 0 ---
      link[0].Cd_X = *p;
      link[0].Cd_Y = *(p + 1);
      link[0].k = 0;
      link[0].vernier = 0 + 1;
      linked_list ++;
      p = p + 3; // 跳过,分隔的逗号,跳到下一个坐标的字母
      */
  } while (*(p - 1) == ',');

  // 路径解析完以后最后一个结点设置为结束符号
  link[linked_list].Cd_X = '\0';
  link[linked_list].Cd_Y = '\0';

对路径进行分析

    /************************************************************************
    函数名称:Quick_reading_FS
    参数:linked_list
    返回值:uint8_t choose
作用:判断相对的位置
	************************************************************************/
uint8_t Quick_reading_FS(uint8_t linked_list)
	{
	    // 例如B7 , B6
    // B == B
	uint8_t choose; // 当前车的朝向
		// 当前结点(也就是坐标)与下一个结点(也就是坐标)的字母进行比较
	    // 如果当前结点(也就是坐标)的 字母 大于 下一个结点(也就是坐标)的字母(如 D > B)
	    // 说明下一个结点(也就是坐标)在当前结点(也就是坐标)的右边(按图排列)
		if (link[ linked_list ].Cd_X > link[ link[ linked_list ].vernier ].Cd_X) choose = 1;
		// 左边
		else if (link[linked_list].Cd_X < link[link[linked_list].vernier].Cd_X) choose = 2;
		else
	    // 当前结点(也就是坐标)的字母,与下一个结点(也就是坐标)的字母相同,即同一条线,则判断数字
		{
	         // 当前结点(也就是坐标)的数字与下一个结点(也就是坐标)的数字进行比较
	         // 如果当前结点(也就是坐标)的数字 的 数字 小于 下一个结点(也就是坐标)的数字(如6 < 7)
	         // 说明下一个结点(也就是坐标)在当前结点(也就是坐标)的上方
	        if (link[ linked_list ].Cd_Y < link[ link[ linked_list ].vernier ].Cd_Y) choose = 3;
	        // 下方
	        else choose = 4;
	}
			return choose;
	}
/***********************************************************************
	调整车头方向函数
	函数名 Change_dir 
	功能:根据下一个点位置方位及 当前车头方向 调整 新的车头方向
	输入参数: dir_b 当前方向 dir_a 调整后方向
	输出参数:无 
	************************************************************************/
	// dir_bef 初始化为0,即开始的时候车头朝上
Change_dir(dir_bef, 0);
	void Change_dir(int dir_b,int dir_a)
	{
	    // int dir_bef ;//初始化当前车头方向,0向上,1向右,2向下,3向左
	    // 例如 dir_b = 0, dir_a = 0
	    // 即要调整的方向在上方
		if((dir_b%2) == (dir_a%2))//判断当前方向与调整后方向是否在一条直线上
		// if(2 == 2)
	{
		   if(dir_b != dir_a)//方向不一致则调头 
	       // if (0 != 0) 不调头
		      Turn_Reverse(2);
	     //  else//方向一致直行 
			 // printf("直行\n");	
		}
		else//不在一条直线上则左转或右转 
		{
			if((dir_a-dir_b== 1) || (dir_a-dir_b == -3))
			  Turn_Right(2);
	    	else
			  Turn_Left(2);		
	}
	}
	
	void Turn_Reverse(uint8_t mode)//调头函数
	{
	    // 往右转两次,调头
	    // mode 是右转的模式
	   // 使用 mode = 2
	   /* 暂时不看 */
   	Turn_Right(mode);
   	Turn_Right(mode);
   }
/************************************************************************
   函数名称:Turn_Right
   参数:mode (右转模式)
   返回值:空
   作用:右转函数的功能实现
   *************************************************************************/
   void Turn_Right(uint8_t mode)//右转函数
   {
   		uint16_t gd = 0xFFFF;	
   		if(mode == 0)//模式0按时间延迟转向
   		{
   			LSpeed=80;
   			RSpeed=-80;
   			
   			Send_UpMotor(LSpeed,RSpeed);
   			delay_ms(500);//延迟时间需精确调整
   			delay_ms(420);//延迟时间需精确调整直线行驶转向550,循迹转向420
   			
   			Send_UpMotor(0,0);
   		}
   		else if(mode == 2)//模式2按保险右转向
   		{
   				int Mp_Value=0;
   				LSpeed =  wheel_SpeedR;
   				RSpeed = -wheel_SpeedR;
   				Send_UpMotor(LSpeed,RSpeed);	
   				while(1)//中间那个灯不灭则继续转向
   				{
   					gd = Get_Host_UpTrack(TRACK_H8);//获取循迹数据
   					if((gd==0xef||gd==0xe7)&&Mp_Value>50)
   						break;
   					else
   						Mp_Value++;
   					delay_ms(10);
   				}
   				Send_UpMotor(0,0);//中间那个灯灭则停止转向
   				//判断小车转90度还是180度.
   				//等待数据
   				if(Mp_Value>150)//判断出寻到白线
   				{
   					if(countL!=0)
   						Turn_Left(4);	//智能左转90
   					else
   					Turn_Left(3);//关闭循迹,定时左转90					
   				}
   				else
   				{
   					if(countR==0)
   						countR=Mp_Value;
   				}

   		}
   		else if(mode == 3)
   		{
   				int Mp_Value=0;
   				LSpeed=85;
   				RSpeed=-85;
   				Send_UpMotor(LSpeed,RSpeed);	
   				while(1)//中间那个灯不灭则继续转向
   				{
   					gd = Get_Host_UpTrack(TRACK_H8);//获取循迹数据
   					if(Mp_Value>110)
   					{
   						break;
   					}
   					else
   					{
   						Mp_Value++;
   					}
   					delay_ms(10);
   				}
   				Send_UpMotor(0,0);//中间那个灯灭则停止转向			
   		}
   		else if(mode==4)//智能右转
   		{
   			int Mp_Value=countR;
   			LSpeed=wheel_SpeedR;
   			RSpeed=-wheel_SpeedR;
   			Send_UpMotor(LSpeed,RSpeed);	
   			while(Mp_Value>0)
   			{
   				delay_ms(10);
   				--Mp_Value;
   			}
   			Send_UpMotor(0,0);	
   		}

   }

   //自动循迹函数
   void Auto_Track(uint8_t  mode)
   {
       /* 暂时不看 */
   	uint16_t gd;
   	Go_Flag = 0;
   	Stop_Flag = 0;
   	Track_Flag = 1;
   	RFID_SpecialTerrain=0;
   	Roadway_mp_syn();//码盘同步
   	Encoder_values[0]=Roadway_mp_Get();//获取码盘值
   	
   	while(Track_Flag == 1)//开始循迹
   	{
   		
   		gd = Get_Host_UpTrack(TRACK_H8);
   		delay_ms(10);
   		ComparisonOTracking(gd,0);	
   		//ComparisonOTracking(gd,mode);
   	}

   }

   /******************************************************************
   函数名称:Intersection_behavior
   参数:RFID_Flag
   返回值:空
   作用:判断十字路口行为
   *******************************************************************/
   void Intersection_behavior(uint8_t RFID_Flag)
    {
   	if(RFID_Flag)
   	{
   		Go_Along(50,450);//到了循迹线再走一段
   		delay_ms(100);
   	}
   }

   // 进行两个结点(也就是坐标)的行进,如果结点(也就是坐标)有任务,则做任务
   for(linked_list=0; link[linked_list].Cd_X != '\0'; linked_list=link[linked_list].vernier)
   {
   	RFID_Flag = 1;
	ReadCard_Flag = 2;//更新读卡任务标准位
   	RFID_Location_Flag = 0;//RFID位置标准位置

   	/****************做任务*******************/
   #if 0	
   	Task(link[linked_list].k);//执行本点对应任务			
   #endif
   	/******************end********************/
   	
   	if(link[ link[ linked_list ].vernier ].Cd_X) // 当前结点的,下一个结点的,字母,不为空,即有下一个结点
   	{
   		uint8_t choose = Quick_reading_FS(linked_list);//判断相对的位置
   		if (choose==2)//判断列坐标大小,如果后者大于前者,则后者在前者左边,调整后方向为3
   		{
   			RFID_special[0]=dir_bef;
   			Change_dir(dir_bef, 3);//调整车头方向
   			dir_bef = 3;
   			RFID_special[1]=dir_bef;
   			Auto_Track(0);//循迹
   			delay_ms(100);
			//判断是否是十字路口
   			Intersection_behavior(RFID_Flag);

   		}
   		else if (choose==1)//判断列坐标大小,如果后者小于前者,则后者在前者右边,调整后方向为1
   		{
   			RFID_special[0]=dir_bef;
   			Change_dir(dir_bef, 1);//调整车头方向
   			dir_bef = 1;
   			RFID_special[1]=dir_bef;
   			Auto_Track(0);//循迹
   			//判断是否是十字路口
			Intersection_behavior(RFID_Flag);
   		}

   		else if (choose==4)//后者行坐标小于前者,则后者在前者下方,调整后方向为2 
   		{
   			RFID_special[0]=dir_bef;
   			Change_dir(dir_bef, 2);//调整车头方向
   			dir_bef = 2;
			RFID_special[1]=dir_bef;
   			Auto_Track(0);//循迹

   			delay_ms(100);
   			//判断是否是十字路口
   			Intersection_behavior(RFID_Flag);
   		}
   		else if (choose==3)//后者行坐标大于前者,则后者在前者上方,调整后方向为0 
   		{
               // int dir_bef;//初始化当前车头方向,0向上,1向右,2向下,3向左
   			RFID_special[0]=dir_bef;
   			Change_dir(dir_bef, 0);
   			dir_bef = 0;
   			RFID_special[1]=dir_bef;
			Auto_Track(0);//循迹
   			delay_ms(100);

   			//判断是否是十字路口
   			Intersection_behavior(RFID_Flag);
   		}
		}
   }

做任务的函数

    //执行任务函数
/* 暂时不看 */
void Task(uint8_t Task_ID)
{
	extern uint8_t Infrared_Tab[6];			//红外数据存放数组
	uint8_t TL=0;
	int i=0;
	extern uint8_t MOKE;
	
	#if 1
	switch(Task_ID)
	{
		
		case 0:
		//开始计时
		LED_display(1);
		delay_s(1);
		//开启无线
		Send_ZigbeeData_To_Fifo(Wir_C,8);
		
		break;
		case 1:	
		dir_bef=3;	
		Turn_Right(2);
		delay_s(1);
		A72_TraffiIdentification();
		break;
	case 2:
	
		break;
		case 3:
		//采集数据
		RecordedData();
		TL=0;
		
		//从车启动
		while(Stop_Flag!=0xA2&&TL<5)
		{
			Send_ZigbeeData_To_Fifo(CCQd1,8);
			Master_slave_interaction();
			delay_ms(500);
			TL++;
		}
		break;
		case 4:
			
		//超声波测距	
		Go_Back(50,450);
		Ultrasonic_LED();

	A72_IdentificationQCode();

		Go_Along(50,400);
		delay_s(1);
		break;
		case 5:
		//智能路灯
		int number=(disa[2]/60);
		int nasdfas=1;
		for(int i=0;i<number;i++)
		{
			
			if(nasdfas>4)
			{
				nasdfas%=4;
			}
			else 
				nasdfas*=number;
		}
		
		nasdfas%=4;
		
		Turn_Right(2);
		delay_s(1);
		Street_lamp(nasdfas+1);
		delay_s(1);
		Turn_Left(2);
		//TFT识别
		Send_ZigbeeData_To_Fifo(H_X,8);//图片下翻

		//接收从车数据
		#if 1 
		
		ReceivTslaveCar();

		#endif
		break;
		case 6:	
		break;
		case 7:	
		//从车地址点
		if(RFID_stop==SET)
		{
			PathAnalysis(READ_RFID);
			delay_s(1);
			while(Stop_Flag!=0xA2)
			{
				Send_ZigbeeData_To_Fifo(CCQd2,8);
				
				Master_slave_interaction();
				delay_s(1);
			}
			
	}			

		delay_s(2);
		Turn_Left(2);
		dir_bef=0;
		TL=0;
		Send_ZigbeeData_To_Fifo(DZ_H,8);
		delay_ms(400);
		Send_ZigbeeData_To_Fifo(DZ_Q,8);
		while(Stop_Flag!=0x07&&TL<5)
		{
			Send_ZigbeeData_To_Fifo(DZ_H,8);
			delay_ms(400);
			Send_ZigbeeData_To_Fifo(DZ_Q,8);
			delay_ms(500);
			DZ_on_of();
			TL++;
		}
		break;
		
		case 8:
		Turn_Right(2);
		SYN_7318_One_test(1,0);
		Turn_Left(2);
		
		break;
		case 9:
		
		Turn_half_Left(2);
		Infrared_Send(Ster_SD,6);
		Turn_half_Ringht(2);
		
		break;
		case 10:		
		break;
		case 11:
		switch(RFID_Position[0])
		{
			case 'E':
				numberOTgarage=2;
				break;
			case 'D':
				numberOTgarage=3;
			break;
			case 'C':
				numberOTgarage=4;		
			break;
		}
		Car_Deal(numberOTgarage,0);
		break;
		case 12:break;
		case 13:break;
		case 14:break;
		case 15:break;
		case 16:break;
		case 17:break;
	}
	#endif
	
	#if 0
	switch(Task_ID)
	{
		case 1:
			Turn_Right(2);
			dir_bef=3;
			A72_TraffiIdentification();
		delay_s(2);
		break;
		case 4:
				A72_IdentificationQCode();
		delay_s(2);
		break;
		case 5:
			A72_vehiclLPlatRecognition();
		delay_s(2);
		break;		
	}
#endif
   }

B7到b6

  1. 判断相对位置
  2. 调整车头方向
  3. 设置全局车头方向变量
  4. 循迹(自动Auto)
  5. 判断十字路口

小车执行任务

中断

GPIO

GPIO 简介

每个通用 I/O 端口包括 4 个 32 位配置寄存器 ( GPIOx_MODER、 GPIOx_OTYPER、GPIOx_OSPEEDR 和 GPIOx_PUPDR)、 2 个 32 位数据寄存器(GPIOx_IDR 和GPIOx_ODR)、 1 个 32 位置位/复位寄存器 (GPIOx_BSRR)、 1 个 32 位锁定寄存器(GPIOx_LCKR) 和 2 个 32 位复用功能选择寄存器( GPIOx_AFRH 和 GPIOx_AFRL)。

GPIO 主要特性

  • 受控 I/O 多达 16 个
  • 输出状态:推挽或开漏 + 上拉/下拉
  • 从输出数据寄存器 (GPIOx_ODR) 或外设(复用功能输出)输出数据
  • 可为每个 I/O 选择不同的速度
  • 输入状态:浮空、上拉/下拉、模拟
  • 将数据输入到输入数据寄存器 (GPIOx_IDR) 或外设(复用功能输入)
  • 置位和复位寄存器 (GPIOx_BSRR),对 GPIOx_ODR 具有按位写权限
  • 锁定机制 (GPIOx_LCKR),可冻结 I/O 配置
  • 模拟功能
  • 复用功能输入/输出选择寄存器(一个 I/O 最多可具有 16 个复用功能)
  • 快速翻转,每次翻转最快只需要两个时钟周期
  • 引脚复用非常灵活,允许将 I/O 引脚用作 GPIO 或多种外设功能中的一种

GPIO 功能描述

根据数据手册中列出的每个 I/O 端口的特性,可通过软件将通用 I/O (GPIO) 端口的各个端口 位分别配置为多种模式:

  • 输入浮空
  • 输入上拉
  • 输入下拉
  • 模拟功能
  • 具有上拉或下拉功能的开漏输出
  • 具有上拉或下拉功能的推挽输出
  • 具有上拉或下拉功能的复用功能推挽
  • 具有上拉或下拉功能的复用功能开漏

每个 I/O 端口位均可自由编程,但 I/O 端口寄存器必须按 32 位字、半字或字节进行访问。 GPIOx_BSRR 寄存器旨在实现对 GPIO ODR 寄存器进行原子读取/修改访问。这样便可确保 在读取和修改访问之间发生中断请求也不会有问题。

通用 I/O (GPIO)

在复位期间及复位刚刚完成后,复用功能尚未激活, I/O 端口被配置为输入浮空模式。 复位后,调试引脚处于复用功能上拉/下拉状态:

  • PA15: JTDI 处于上拉状态
  • PA14: JTCK/SWCLK 处于下拉状态
  • PA13: JTMS/SWDAT 处于下拉状态
  • PB4: NJTRST 处于上拉状态
  • PB3: JTDO 处于浮空状态

当引脚配置为输出后,写入到输出数据寄存器 (GPIOx_ODR) 的值将在 I/O 引脚上输出。可 以在推挽模式下或开漏模式下使用输出驱动器(输出 0 时仅激活 N-MOS)。 输入数据寄存器 (GPIOx_IDR) 每隔 1 个 AHB1 时钟周期捕获一次 I/O 引脚的数据。 所有 GPIO 引脚都具有内部弱上拉及下拉电阻,可根据 GPIOx_PUPDR 寄存器中的值来打 开/关闭。

I/O 引脚复用器和映射

微控制器 I/O 引脚通过一个复用器连接到板载外设/模块,该复用器一次仅允许一个外设的复 用功能 (AF) 连接到 I/O 引脚。这可以确保共用同一个 I/O 引脚的外设之间不会发生冲突。 每个 I/O 引脚都有一个复用器,该复用器采用 16 路复用功能输入( AF0 到 AF15) ,可通过 GPIOx_AFRL(针对引脚 0 到 7)和 GPIOx_AFRH(针对引脚 8 到 15)寄存器对这些输入 进行配置:

  • 完成复位后,所有 I/O 都会连接到系统的复用功能 0 (AF0)。
  • 外设的复用功能映射到 AF1 至 AF13。
  • Cortex-M4F EVENTOUT 映射到 AF15。

除了这种灵活的 I/O 复用架构之外,各外设还可以将复用功能映射到不同 I/O 引脚,这可以 优化小型封装中可用外设的数量

要将 I/O 配制成所需功能,请按照以下步骤操作:

  1. 系统功能

将 I/O 连接到 AF0,然后根据所用功能进行配置: — JTAG/SWD:在各器件复位后,会将这些引脚指定为专用引脚,可供片上调试模块立即使用(不受 GPIO 控制器控制)。 — RTC_REFIN:此引脚应配置为输入浮空模式。 — MCO1 和 MCO2:这些引脚必须配置为复用功能模式。

  1. GPIO

在 GPIOx_MODER 寄存器中将所需 I/O 配置为输出或输入。

  1. 外设复用功能

对于 ADC 和 DAC,在 GPIOx_MODER 寄存器中将所需 I/O 配置为模拟通道。 对于其它外设: — 在 GPIOx_MODER 寄存器中将所需 I/O 配置为复用功能 — 通过 GPIOx_OTYPER、 GPIOx_PUPDR 和 GPIOx_OSPEEDER 寄存器,分别选 择类型、上拉/下拉以及输出速度 — 在 GPIOx_AFRL 或 GPIOx_AFRH 寄存器中,将 I/O 连接到所需 AFx

  1. EVENTOUT

配置用于输出 Cortex-M4F EVENTOUT 信号的 I/O 引脚(通过将其连接到 AF15) 注意: EVENTOUT 不会映射到以下 I/O 引脚: PC13、 PC14、 PC15、 PH0、 PH1 和 PI8。 有关系统和外设的复用功能 I/O 引脚映射的详细信息,请参见数据手册中的“复用功能 映射”表。

I/O 端口控制寄存器

每个 GPIO 有 4 个 32 位存储器映射的控制寄存器( GPIOx_MODER、 GPIOx_OTYPER、GPIOx_OSPEEDR、 GPOIx_PUPDR), 可配置多达 16 个 I/O。 GPIOx_MODER 寄存器用于选择 I/O 方向(输入、输出、 AF、模拟)。 GPIOx_OTYPER 和 GPIOx_OSPEEDR 寄存器分别用于选择输出类型(推挽或开漏)和速度 (无论采用哪种 I/O 方向,都会直接将 I/O 速度引 脚连接到相应的 GPIOx_OSPEEDR 寄存器位)。无论采用哪种 I/O 方向, GPIOx_PUPDR 寄存器都用于选择上拉/下拉。

I/O 端口数据寄存器

每个 GPIO 都具有 2 个 16 位数据寄存器:输入和输出数据寄存器( GPIOx_IDR 和GPIOx_ODR)。 GPIOx_ODR 用于存储待输出数据,可对其进行读/写访问。通过 I/O 输入的数据存储到输入数据寄存器 (GPIOx_IDR) 中, 它是一个只读寄存器。 有关寄存器说明的详细信息,请参见第 7.4.5 节: GPIO 端口输入数据寄存器 (GPIOx_IDR) (x = A..I) 和第 7.4.6 节: GPIO 端口输出数据寄存器 (GPIOx_ODR) (x = A..I)。

I/O 数据位操作

置位复位寄存器 (GPIOx_BSRR) 是一个 32 位寄存器,它允许应用程序在输出数据寄存器(GPIOx_ODR) 中对各个单独的数据位执行置位和复位操作。 置位复位寄存器的大小是GPIOx_ODR 的二倍。 GPIOx_ODR 中的每个数据位对应于 GPIOx_BSRR 中的两个控制位: BSRR(i) 和BSRR(i+SIZE)。 当写入 1 时, BSRR(i) 位会置位对应的 ODR(i) 位。当写入 1 时,BSRR(i+SIZE) 位会清零 ODR(i) 对应的位。 在 GPIOx_BSRR 中向任何位写入 0 都不会对 GPIOx_ODR 中的对应位产生任何影响。 如果在 GPIOx_BSRR 中同时尝试对某个位执行置位和清零操作,则置位操作优先。 使用 GPIOx_BSRR 寄存器更改 GPIOx_ODR 中各个位的值是一个“单次”操作,不会锁定GPIOx_ODR 位。 随时都可以直接访问 GPIOx_ODR 位。 GPIOx_BSRR 寄存器提供了一种执行原子按位处理的方法。 在对 GPIOx_ODR 进行位操作时,软件无需禁止中断:在一次原子 AHB1 写访问中,可以修改一个或多个位。

GPIO 锁定机制

通过将特定的写序列应用到 GPIOx_LCKR 寄存器,可以冻结 GPIO 控制寄存器。冻结的寄存器包括 GPIOx_MODER、 GPIOx_OTYPER、 GPIOx_OSPEEDR、 GPIOx_PUPDR、GPIOx_AFRL 和 GPIOx_AFRH。 要对 GPIOx_LCKR 寄存器执行写操作,必须应用特定的写/读序列。当正确的 LOCK 序列应用到此寄存器的第 16 位后, 会使用 LCKR[15:0] 的值来锁定 I/O 的配置(在写序列期间,LCKR[15:0] 的值必须相同)。 将 LOCK 序列应用到某个端口位后,在执行下一次复位之前,将无法对该端口位的值进行修改。 每个 GPIOx_LCKR 位都会冻结控制寄存器 (GPIOx_MODER、GPIOx_OTYPER、 GPIOx_OSPEEDR、 GPIOx_PUPDR、 GPIOx_AFRL 和 GPIOx_AFRH)中的对应位。 LOCK 序列(参见第 7.4.8 节: GPIO 端口配置锁定寄存器 (GPIOx_LCKR) (x = A..I))只能通过对 GPIOx_LCKR 寄存器进行字( 32 位长)访问的方式来执行, 因为 GPIOx_LCKR 的第 16 位必须与 [15:0] 位同时置位。 有关详细信息,请参见第 7.4.8 节: GPIO 端口配置锁定寄存器 (GPIOx_LCKR) (x = A..I) 中的 LCKR 寄存器说明。

外部中断线/唤醒线

所有端口都具有外部中断功能。要使用外部中断线,必须将端口配置为输入模式,请参见 第 10.2 节:外部中断/事件控制器 (EXTI)和第 10.2.3 节:唤醒事件管理。

输入配置

对 I/O 端口进行编程作为输入时:

  • 输出缓冲器被关闭
  • 施密特触发器输入被打开
  • 根据 GPIOx_PUPDR 寄存器中的值决定是否打开上拉和下拉电阻
  • 输入数据寄存器每隔 1 个 AHB1 时钟周期对 I/O 引脚上的数据进行一次采样
  • 对输入数据寄存器的读访问可获取 I/O 状态

图 20 说明了 I/O 端口位的输入配置

GPIO 寄存器

本节对 GPIO 寄存器进行了详细介绍。 有关寄存器位、寄存器偏移地址和复位值的汇总,请参见表 32。 可通过字节( 8 位)、半字( 16 位)或字( 32 位)对 GPIO 寄存器进行访问。

发送数据

过程

  1. 往某个结构体写入数据(指令)
    1. 判断结构体是否可用
    2. 一个一个数据写入,并返回是否成功
  2. 将数据读入缓存区(读入的步骤和写入类似)
  3. 从缓存区将数据(指令)写入Can总线中,所有节点设备都可以接收到数据,
  4. 节点数据解析数据(指令)

调用SendS_InfoData_To_Fifo函数


static uint8_t Car_1[8]={0x55,0x0D,0x01,0x01,0x00,0x00,0x02,0xBB};  //到达第一层
static uint8_t Car_2[8]={0x55,0x0D,0x01,0x02,0x00,0x00,0x03,0xBB};  //到达第二层
static uint8_t Car_3[8]={0x55,0x0D,0x01,0x03,0x00,0x00,0x04,0xBB};  //到达第三层
static uint8_t Car_4[8]={0x55,0x0D,0x01,0x04,0x00,0x00,0x05,0xBB};  //到达第四层
static uint8_t Car_R_F[8]={0x55,0x0D,0x02,0x01,0x00,0x00,0x03,0xBB};//请求回传立体车库所在层数
static uint8_t Car_R_I[8]={0x55,0x0D,0x02,0x02,0x00,0x00,0x04,0xBB};//请求回传立体车库前后侧红外状态



typedef struct _Fifo_Drv_Struct
{
	uint32_t ml;
	uint32_t rp;
	uint32_t wp;	
	uint8_t *buf;
}Fifo_Drv_Struct;

Fifo_Drv_Struct Fifo_ZigbTx;

// 结构体初始化
void FifoDrv_Init(Fifo_Drv_Struct *p,uint8_t c)
{
	if(p != _NULL)
	{
		if(p->ml > 1)
		{
			p->wp = 0;
			p->rp =  p->ml-1;
			memset(p->buf,c,p->ml);
		}
	}	
}

// 例如发送
// 
Send_ZigbeeData_To_Fifo(Car_1,8); // go.c -> 1484 line
/**
函数功能:将数据发送至ZigBee模块
参    数:无
返 回 值:无
*p = Car_1, len = 8
*/
void Send_ZigbeeData_To_Fifo(u8 *p, u8 len)
{
FifoDrv_BufWrite(&Fifo_ZigbTx, p, len);
// FifoDrv_Bufwrite(&Fifo_ZigbTx, Car_1, 8);
}


/*
往特定地址写入数据
*/
uint32_t FifoDrv_BufWrite(Fifo_Drv_Struct *p,uint8_t *buf,uint32_t l)
{
// *p = Fifo_ZigbTx, *buf = Car_1, l = 8
// 函数调用等于 FifoDrv_Bufwrite(Fifo_ZigbTx, Car_1, 8);
	uint32_t Rt = 0;
	int i=l;
	// int i = 8;
	while(l--)
	{
		if(Rt==6&&8==i)
		{
				buf[6]=((buf[5]+buf[4]+buf[3]+buf[2]))%256;
				// 做校验和的计算
		}
		// 一个一个数据写入
		if(FifoDrv_WriteOne(p,buf[Rt]) == 0)
			break;
		Rt++;
	}
	// 返回写入了多少位数据
	return Rt;
}

// 一个一个数据写入
uint8_t FifoDrv_WriteOne(Fifo_Drv_Struct *p,uint8_t d)
{
// *p = Fifo_ZigbTx, d = buf[Rt] -> {buf[0], buf[1], buf[2]}
// 函数调用等于 FifoDrv_WriteOne(Fifo_ZigbTx, Car_1[x])
	uint8_t Rt = 0;
	// 如果可用返回1
	if(FifoDrv_CheckWriteEn(p))
	{
		p->buf[p->wp++] = d;
		if(p->wp >= p->ml)
			p->wp = 0;
		Rt = 1;
	}
	// 写入成功返回1
	return Rt;
}

// 检查结构体是否可用
uint8_t FifoDrv_CheckWriteEn(Fifo_Drv_Struct *p)
{
// *p = Fifo_ZigbTx
// 函数调用等于 FifoDrv_CheckWriteEn(Fifo_ZigbTx);
	uint8_t Rt = 0;
	if(FifoDrv_StructCheck(p))
	{
		if(p->wp != p->rp)
			Rt = 1;
	}
	// 如果可用返回1
	return Rt;
}

/*
// 检查结构体是否可用
*/
uint8_t FifoDrv_StructCheck(Fifo_Drv_Struct *p)
{
// *p = Fifo_ZigbTx
// 函数调用等于 FifoDrv_StructCheck(Fifo_ZigbTx);
	uint8_t Rt = 0;
	if(p != _NULL)
	{
		if(p->ml > 1)
		{
			if((p->buf != _NULL)
			   &&(p->wp < p->ml)
				&&(p->rp < p->ml)
					)
				Rt = 1;
		}
	}
	// 如果可用返回1
	return Rt;
}

发送到Can总线

// Can总线数据监测
void CanP_CanTx_Check(void)
{
	uint8_t tmbox, i, f = 1;
	while (f)
	{
		f = 0;
		i = FifoDrv_BufRead(&Fifo_Info, ctbuf, 8); // 调试信息
		if (i)
		{
			CanDrv_WhaitTxEmpty();
			CanDrv_TxData(ctbuf, i, CAN_SID_HL(ID_DISP, 0), 0, &tmbox);
			f = 1;
		}
		i = FifoDrv_BufRead(&Fifo_WifiTx, ctbuf, 8); // wifi信息
		if (i)
		{
			CanDrv_WhaitTxEmpty();
			CanDrv_TxData(ctbuf, i, CAN_SID_HL(ID_WIFI, 0), 0, &tmbox);
			f = 1;
		}

		i = FifoDrv_BufRead(&Fifo_ZigbTx, ctbuf, 8); // Zigbee信息
		if (i)
		{
			CanDrv_WhaitTxEmpty();
			// 发送到Can总线里面
			CanDrv_TxData(ctbuf, i, CAN_SID_HL(ID_ZIGBEE, 0), 0, &tmbox);
			f = 1;
		}
	}
}

控制各种标志物

LED 显示器

使用Zigbee

控制道闸

使用Zigbee

语音播报

使用Zigbee

智能路灯

使用红外发射控制

控制立体显示标志物

使用红外发射控制

烽火台

使用红外发射控制

通过ETC

使用Zigbee

TFT 显示标志物

使用Zigbee

无线充电

使用Zigbee

智能交通灯

使用Zigbee

控制立体车库

获取当前立体车库状态

// 请求回传立体车库所在层数
Send_ZigbeeData_To_Fifo(Car_R_F,8);
// 获取当前车库状态
Can_ZigBeeRx_carport();

把车库降至1层

int Stereo_loop=1;
	//判断车库在第几层,并发指令降到第一层
	int i=0;
	while(Stop_Flag!=0x09)
	{
		delay_ms(400);		
		Send_ZigbeeData_To_Fifo(Car_R_F,8);
		delay_ms(400);
		Can_ZigBeeRx_carport();
		delay_ms(400);
		// 发送降到第一层的指令
		Send_ZigbeeData_To_Fifo(Car_1,8);
	}
	//倒车
	Go_Back(100,2000);
	//标准入库
	

获取车库状态(停车状态)

// 请求回传立体车库所在层数
Send_ZigbeeData_To_Fifo(Car_R_F,8);
// 获取当前车库状态
Can_ZigBeeRx_carport();

把车库升至指定层数

// 发送降到第一层的指令
Send_ZigbeeData_To_Fifo(Car_1,8);

两车交互

使用Zigbee发送/接收数据

Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化