一个单片机调试小工具的编程思路

发布者:innovator7最新更新时间:2024-03-20 来源: elecfans关键字:单片机  编程思路 手机看文章 扫描二维码
随时随地手机看文章


  {


   if (byteArray[i] == 0xFF)


  {


    count++;


  }


  }


  if (count >= PARAMENT_MAX_LENTH)


  {


  timeout = true;


 }


 else


  {


   if (function_send)              //获取函数返回值


  {


    function_send = false;




    ushort crc1 = 0;


    crc1 = (ushort)byteArray[RETURN_MAX_LENTH - 2];


    crc1 = (ushort)(crc1 << 8);


    crc1 = (ushort)(crc1 | (ushort)byteArray[RETURN_MAX_LENTH - 1]);




    byte[] byte_Array = new byte[RETURN_MAX_LENTH - 2];


    for (uint i = 0; i < RETURN_MAX_LENTH - 2; i++)


   {


     byte_Array[i] = byteArray[i];


   }


   CRC16 c = new CRC16();


   ushort crc = c.GetCRC16(byte_Array);




   if(crc == crc1)


   {


    TypeUnion return_data = (TypeUnion)BytesToStuct(byte_Array, typeof(TypeUnion));


    String s = TypeTransferToString(function_table.function_table[select_function_index].Function_Return, return_data);




    RecivedTextBox.Text = s;


   }


   else


   {


    timeout = true;


   }


  }


 }




 }


 else                  //超过设置的超时时间,直接关闭串口并报错


{


 timeout = true;




  SerialPort.Close();


  ControlSerialButton.Text = '打开串口';


  COMComboBox.Enabled = true;


  BaudRateComboBox.Enabled = true;


  ParityBitsComboBox.Enabled = true;


  StopBitComboBox.Enabled = true;


  DataBitsComboBox.Enabled = true;


      


   MessageBox.Show('通讯超时!已关闭串口!');


  }




    return timeout;}


三、下位机的处理


3.1 接收处理


本来打算使用DMA+空闲中断接收命令字,但考虑到有些低端的单片机没有空闲中断,同时实际使用中出现数据丢失会造成持续的等待,所以直接使用单字节中断接收的方案。在接收到固定的字节后,标志位data_recived置一,并将数据拷贝出来。



void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)                //接收中断

{


  unsigned char i = 0;


  


  HAL_TIM_Base_Stop_IT(&htim3);


  __HAL_TIM_SET_COUNTER(&htim3, 0);


  data[data_length] = recv_data;


  


  data_length++;


  


  if(data_length < MAX_RECIVE_LENGTH)


 {


   HAL_TIM_Base_Start_IT(&htim3);


  }


 else


  {


    data_length = 0;


        


    data_recived = 1;


        


   for(i = 0;i < MAX_RECIVE_LENGTH;i++)


  {


    r_data[i] = data[i];


  }


 }


      


 HAL_UART_Receive_IT(&huart1, &recv_data, 1);


}


3.2 超时处理


由于在实际的数据收发中,会出现数据丢失而造成上位机发送完毕但下位机并未全部接受,从而下位机一直处于等待的情况。为了解决这一情况,引入一个定时为200Hz的定时器。在进入接收中断后,先关闭清空定时器,读取接收的数据后再开启定时。如果出现数据丢失而造成下位机等待的情况,则会引发定时中断。在定时中断内直接清空接收计数器,并给上位机发送超时指令。




void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)                                                                        //超时中断,超时时间为5ms,一旦超时就发送8字节0xFF

{


      unsigned char i = 0;


        


      HAL_TIM_Base_Stop_IT(&htim3);


      __HAL_TIM_SET_COUNTER(&htim3, 0);


        


      data_length = 0;


        


      for(i = 0;i < PARAMENT_MAX_LENTH;i++)


     {


         returndata[i] = 0xFF;


      }


                


      crc = crc16(returndata, PARAMENT_MAX_LENTH);        


      returndata[PARAMENT_MAX_LENTH] = crc >> 8;


      returndata[PARAMENT_MAX_LENTH + 1] = crc;


      HAL_UART_Transmit(&huart1, returndata, 10, 0xFF);


}

3.3 函数指针


通过周期调用void Recived_Command_Handle(void)来实现上位机发送的函数调试命令字。



void Recived_Command_Handle(void)

{


  unsigned char i = 0;


  unsigned char j = 0;


        


  if(data_recived)


  {


   data_recived = 0;


        


   crc_16 = (r_data[49] << 8) | r_data[50];


      


   r_data[MAX_RECIVE_LENGTH - 2] = 0;


   r_data[MAX_RECIVE_LENGTH - 1] = 0;


   crc = crc16(r_data, MAX_RECIVE_LENGTH);                                                                        //CRC_CITT校验


        


   if(crc == crc_16)


   {


     num = r_data[0];                                                                                                  //获取参数数量


        


     for(i = 0;i < PARAMENT_MAX_LENTH;i++)                                                                                                                                                                                                                        //获取地址


     {


      addr.u_char[i] = r_data[1 + i];


      }


          


     for(i = 0;i < 5;i++)                                                                                                //获取参数


    {


       for(j = 0;j < PARAMENT_MAX_LENTH;j++)


        {


         paramen[i].u_char[j] = r_data[(1 + PARAMENT_MAX_LENTH) + PARAMENT_MAX_LENTH*i + j];


       }


      }


          


     if(addr.ul != 0)                                                                                                        //获取返回值


     {


       for(i = 0;i < PARAMENT_MAX_LENTH;i++)


      {


       return_data.u_char[i] = 0;


       }


              


      return_data = function(addr.ul,num,paramen);


    }


              


     for(i = 0;i < PARAMENT_MAX_LENTH;i++)


     {


      returndata[i] = return_data.u_char[i];


    }


    crc = crc16(return_data.u_char, PARAMENT_MAX_LENTH);  


    returndata[PARAMENT_MAX_LENTH] = crc >> 8;


     returndata[PARAMENT_MAX_LENTH + 1] = crc;


      HAL_UART_Transmit(&huart1, returndata, 10, 0xFF);                                


    }


   }


}


其中函数实现由parameter_kind_union function(unsigned int function_addr,unsigned char paramenter_num,parameter_kind_union *paramenter)完成。



parameter_kind_union function(unsigned int function_addr,unsigned char paramenter_num,parameter_kind_union *paramenter)

{


  void *p = (void *)function_addr;


  parameter_kind_union return_data;


  


  switch(paramenter_num)


 {


   case 0: return_data.ull = (*(unsigned int(*)())p)();


      break;


   case 1: return_data.ull = (*(unsigned int(*)())p)(PARAMENT_TRANSFER(paramenter[0]));


      break;


   case 2: return_data.ull = (*(unsigned int(*)())p)(PARAMENT_TRANSFER(paramenter[0]),PARAMENT_TRANSFER(paramenter[1]));


      break;


   case 3: return_data.ull = (*(unsigned int(*)())p)  (PARAMENT_TRANSFER(paramenter[0]),PARAMENT_TRANSFER(paramenter[1]),PARAMENT_TRANSFER(paramenter[2]));


       break;


    case 4: return_data.ull = (*(unsigned int(*)())p)(PARAMENT_TRANSFER(paramenter[0]),PARAMENT_TRANSFER(paramenter[1]),PARAMENT_TRANSFER(paramenter[2]),PARAMENT_TRANSFER(paramenter[3]));


        break;


   case 5: return_data.ull = (*(unsigned int(*)())p)(PARAMENT_TRANSFER(paramenter[0]),PARAMENT_TRANSFER(paramenter[1]),PARAMENT_TRANSFER(paramenter[2]),PARAMENT_TRANSFER(paramenter[3]),PARAMENT_TRANSFER(paramenter[4]));


       break;


   }


  


   return return_data;


}


#definePARAMENT_TRANSFER(p)(*(volatileunsignedint*)((unsignedint)&p))

其操作含义如下:


1)&p含义为取变量p地址;


2)(unsigned int)&p)含义为将取得的地址强制转换为unsigned int;


3)(volatile unsigned int*)((unsigned int)&p)含义为将数字转换为unsigned int类型的指针;


4)*(volatile unsigned int*)((unsigned int)&p)含义为取得该地址内的数据;

[1] [2] [3] [4] [5]
关键字:单片机  编程思路 引用地址:一个单片机调试小工具的编程思路

上一篇:MMC中断的特点及解决方案
下一篇:SAR ADC内部结构

推荐阅读最新更新时间:2024-11-14 09:32

MSP430单片机理论复习知识点
纵观微处理器的发展,一是朝着具有复杂数据运算、高速通信、信息处理等功能的高性能计算机系统方向发展;二是产生了一种将中央处理器,存储器,I/O接口电路以及连接他们的总线都集成一块芯片上的计算机。单片机在设计上主要突出了控制功能,调整了接口配置,在单一芯片上制成了结构完整的计算机。 目前最常用的3中可编程处理器:微控制器(MCU)、微处理器(MPU)、数字信号处理器(DSP); 单片机可应用的领域:工业控制(工业机器人)、智能化仪器仪表(温度湿度的测量)、日常生活钟的电器产品(MP3)、计算机网络与通信(以太网)、计算机外部设备(微型打印机); 单片机的结构特点:时钟频率比通用MPU和DSP低;功耗低;字长一般为8-32位;内
[单片机]
单片机的定时器中断0
定时器工作的流程可以按照这个顺序(以51为例用定时器0方式一产生50毫秒的定时) 1、确定使用哪个定时器,使用哪种方式,这一步通过TMOD设置,TMOD的低四位是设置定时器0的,高四位是用来设置定时器1的,其中的M0,M1是用来设置定时器工作在哪种方式,GATE一般用不要设置,C/T是选择计数模式还是定时模式的,如:TMOD = 0X01,就说明定时器0工作在方式1。 2、接下来就要设置定时的时间,用定时器定时50毫秒,可以用这种方式TH0 = (65535 - 50000) / 256,TL0 = (65535 - 50000) % 256;可以这样理解:因为这是定时器的初值,也就是说计数脉冲就是在这个数的基础上向上递增,到达65
[单片机]
<font color='red'>单片机</font>的定时器中断0
51单片机汇编语言数字时钟
数字时钟proteus+ 51单片机+LCD1602+汇编语言+1602器件资料,适合做单片机课程结课作品 单片机汇编源程序如下: ;/******************************************************************************** ; LCD1602 时钟显示Cekong time测控何小双 ;********************************************************************************/ RS EQU P2.0; //控制端接口 R_W
[单片机]
51<font color='red'>单片机</font>汇编语言数字时钟
51单片机IO口模拟串口通讯C源程
51 IO口模拟串口通讯C源程 #include reg51.h sbit BT_SND =P1^0; sbit BT_REC =P1^1; #define MODE_QUICK #define F_TM F0 #define TIMER0_ENABLE TL0=TH0; TR0=1; #define TIMER0_DISABLE TR0=0; sbit ACC0= ACC^0; sbit ACC1= ACC^1; sbit ACC2= ACC^2; sbit ACC3= ACC^3; sbit ACC4= ACC^4; sbit ACC5= ACC^5; sbit ACC6= ACC^6; sbit ACC7= ACC^
[单片机]
单片机MCU内存分配
谈到内存,我们都会想到PC,对于单片机或者arm来说也是存在内存的,简单的理解是:内存嘛……就是存放东西的地方,只不过这个东西是数据而已,好了,还是把重点放在mcu上面,对于一款mcu来说,在性能描述的时候都会告诉sram,flash的容量大小,对于初学者来说,也不会去考虑和理会这些东西,拿到东西就只用。其实不然,这些量都是十分重要的,仔细想想,代码为什么可以运行,代码量是多少,定义的int、short等等类型的变量究竟是怎么分配和存储的,这些问题都和内寸有关系。 首先单片机的内存可以大小分为ram和rom,这里就不再解释ram和rom的区别了,我们可以将其等效为flash和sram,其中根据flash和sram的定义可得,
[单片机]
飞思卡尔推出面向软件工程师的汽车微控制器产品线S32K MCU
采用ARM Cortex 技术的新汽车架构实现了软件和硬件可扩展性,通过面向未来的特性和最佳的软件复用加快开发 2015年6月23日,德克萨斯州奥斯汀(2015年飞思卡尔技术论坛)讯-随着新汽车中芯片内容和复杂性的不断增加,未来的汽车发展对软件愈发依赖。新汽车通常集成了超过1亿行内置代码,比大多数民用客机的代码数量还要多。虽然软件带来了令人兴奋的创新机会,但同时也增加了复杂性,催生了大量的代码维护和上市速度挑战。因此,汽车电子供应商现在投入到软件领域的开发资源超过了在硬件方面的开发资源。 为了应对这些挑战,飞思卡尔半导体推出了首个旨在大大加快和简化软件开发的汽车微控制器产品线S32K。S32K基于广泛采用的
[单片机]
PIC单片机对清洁护理机的设计
引言 随着我国老龄化进程的加剧,当今社会中存在着一种因失去生活自理能力而“长期卧床的弱势群体”,特别是那些几乎无意识的弱势群体,他们需要被人长期照顾,特别是他们的大小便的清洁处理。然而由于该弱势群体数量大、护理人员紧缺和护理费用高等问题,导致这些弱势群体的家庭护理矛盾日益凸显。目前市场上的长期卧床病人大小便清洁护理机在“智能护理”方面己比较完善,已经具有大小便自动识别与回收、温水清洗与自动烘干等功能,达到了“人性化”护理的要求,但在使用过程中仍然需要专门的“陪护人员”,对于绝大多数现代家庭而言,无论从人力还是财力,这都将是一个沉重的负担,同时也限制了大小便清洁护理机在家庭中的推广使用,因此,社会迫切需要一种在现有护理功能的基础上能
[单片机]
PIC<font color='red'>单片机</font>对清洁护理机的设计
PIC单片机AD通道转换函数问题解析
  AD转换   D转换就是模数转换。顾名思义,就是把模拟信号转换成数字信号。主要包括积分型、逐次逼近型、并行比较型/串并行型、Σ-Δ调制型、电容阵列逐次比较型及压频变换型。   A/D转换器是用来通过一定的电路将模拟量转变为数字量。模拟量可以是电压、电流等电信号,也可以是压力、温度、湿度、位移、声音等非电信号。但在A/D转换前,输入到A/D转换器的输入信号必须经各种传感器把各种物理量转换成电压信号。   AD转换分类   1)积分型(如TLC7135)   积分型AD工作原理是将输入电压转换成时间(脉冲宽度信号)或频率(脉冲频率),然后由定时器/计数器获得数字值。其优点是用简单电路就能获得高分辨率, 但缺点是由于转换精度
[单片机]
PIC<font color='red'>单片机</font>AD通道转换函数问题解析
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
更多往期活动
随便看看

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved