STM32
直播中

木頭瓶子

11年用户 557经验值
擅长:353304
私信 关注
[问答]

怎样通过Matlab脚本去写入C代码呢

手写代码有哪几个特点呢?
怎样通过matlab脚本去写入C代码呢?

回帖(1)

高澜栖

2021-11-19 14:43:03
  本文介绍一种通过Matlab脚本写入C代码的方法,以实现通过管理表格文件就可以生成具有一定规律的C代码,从而减少人工手写代码的工作量。
  1 问题引入
  在MBD中,并非所有的代码都适合通过Simulink模型生成。通常来说,会用Simulink模型搭建控制算法,然后将其生成代码。
  而一些与配置相关的功能,则会通过人工手写C代码的方式完成。譬如EEPROM配置代码,CAN帧配置代码等,往往通过直接手写会比Simulink建模更加容易实现。
  这种手写代码有几个特点:
  改动比较频繁。如果需求经常变,那么配置的代码就会经常变。
  具有一定规律。比方说很多EEPROM变量按照同种方式赋值给结构体,或者CAN信号按照某种规律装填到某一帧里面
  人工手写容易出错。代码看起来眼花缭乱,一不留神就会写错。
  所以针对这些问题,博主比较喜欢通过Excel表格,把CAN、EEPROM这些变量的属性管理起来,然后通过脚本读取表格,自动写入C文件和头文件。每次需求变更的时候,只要更新好表格在运行脚本,那然后生成C文件只是一瞬间的事情。
  2 需求示例
  由于CAN、HWIO和EEPROM的代码在汽车软件团队中的保密级别比较高,所以就没法通过这些来举例了。博主打算通过比较常见的stm32f103的GPIO配置代码,来说明整个流程和思路。
  熟悉stm32GPIO配置的博友肯定对下面的led.c的C代码不会陌生,因为这是经典的跑马灯实验中初始化LED灯的C代码。
  #include “led.h”
  void LED_Init(void)
  {
  GPIO_InitTypeDef GPIO_InitStructure;
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOE, ENABLE);
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOB, &GPIO_InitStructure);
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOB, &GPIO_InitStructure);
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOE, &GPIO_InitStructure);
  }
  函数主体中包含了使能时钟和引脚的GPIO配置等,其模式都比较固定。
  上述C代码中配置了三个引脚PB5,PB6和PE5。可以归纳为一张Excel表格led.xlsx如下:
  
  通过Matlab脚本解析这张表格,提取出GPIO信息,就可以写出对应的led.c文件。
  博友如果想运行下面的脚本,可以在Matlab当前路径先新建一个led.xlsx表格,并拷贝下面的表格内容。
  [tr]GPIOGPIO_PinGPIO_ModeGPIO_Speed[/tr]
  BGPIO_Pin_5GPIO_Mode_Out_PPGPIO_Speed_50MHz
  BGPIO_Pin_6GPIO_Mode_Out_PPGPIO_Speed_50MHz
  EGPIO_Pin_5GPIO_Mode_Out_PPGPIO_Speed_50MHz
  3 示例脚本
  这一章节直接把整个生成C文件的函数都贴出来,下一章会一点点的解释博主的思路。
  function ManualCode()
  %% step1 读取表格信息
  [~,~,Excel_Cell] = xlsread(‘led.xlsx’,‘led’);
  CodeText = ‘’;
  %% step2 将代码内容写入变量CodeText中
  %#include头文件
  CodeText = [CodeText,‘#include “led.h”’,newline,newline];
  %函数以及结构体
  CodeText = [CodeText,‘void LED_Init(void)’,newline,‘{’,newline,‘ GPIO_InitTypeDef GPIO_InitStructure;’,newline,newline];
  %使能端口时钟
  RCCParamater = ‘’;
  for row = 2:size(Excel_Cell,1)
  Paramater = [‘RCC_APB2Periph_GPIO’,Excel_Cell{row,1}];
  if ~contains(RCCParamater,Paramater)
  RCCParamater = [RCCParamater,Paramater,‘|’];
  end
  end
  RCCParamater = RCCParamater(1:end-1);
  CodeText = [CodeText,‘ RCC_APB2PeriphClockCmd(’,RCCParamater,‘, ENABLE);’,newline,newline];
  %端口配置
  for row = 2:size(Excel_Cell,1)
  CodeText = [CodeText,‘ GPIO_InitStructure.GPIO_Pin = ’,Excel_Cell{row,2},‘;’,newline];
  CodeText = [CodeText,‘ GPIO_InitStructure.GPIO_Mode = ’,Excel_Cell{row,3},‘;’,newline];
  CodeText = [CodeText,‘ GPIO_InitStructure.GPIO_Speed = ’,Excel_Cell{row,4},‘;’,newline];
  CodeText = [CodeText,‘ GPIO_Init(GPIO’,Excel_Cell{row,1},‘, &GPIO_InitStructure);’,newline,newline];
  end
  CodeText = [CodeText,‘}’,newline];
  %% step3 将变量CodeText写入led.c文件中
  fid = fopen(‘led.c’,‘w’);
  fprintf(fid,CodeText);
  fclose(fid);
  end
  4 脚本说明
  4.1 step1 读取表格信息
  第一步很简单,通过xlsread函数把led.xlsx的表格信息读出来,存放在一个单元数组Excel_Cell中。
  
  然后建了一个空的字符串变量CodeText,在后面用于不断地写入C文件内容的信息,最后再一股脑地存到文件中。
  4.2 step2 将代码内容写入变量CodeText中
  这个step是主体部分,会从头到尾一点一点地写C文件的内容。
  4.2.1 头文件、函数名、定义结构体
  头文件、函数名和定义结构体都是固定的代码,直接写在CodeText变量中就行了。
  
  脚本运行到这一步,就已经把头文件、函数名、定义结构体写进了CodeText变量中。
  
  4.2.2 使能端口时钟
  使能端口时钟这行代码就和表格的第一列相关了。可以看出一共有B和E两种GPIO引脚。
  
  所以代码中的参数应该把B和E都带上。
  
  Matlab脚本中对第一列进行循环和判断,写入CodeText变量。
  
  4.2.3 端口配置
  表格的B,C,D列都是端口配置相关信息,通过一个for循环依次写入。写完以后在变量后面再加个花括号}。
  
  4.3 step3 将变量CodeText写入led.c文件中
  用fopen函数和fprintf函数,把包含文件内容的CodeText字符串写到led.c文件中,就完成了这个代码自动写入的过程。
  5 总结
  本文的例子比较简单,也几乎没有涉及字符串操作,只是展现了一个基本思路。基本思路就是通过表格管理代码中的一些关键信息,然后通过脚本识别表格的信息,自动写出C文件或头文件。
  这个方法的特点是,在前期制作表格模板以及写脚本的过程中需要花费很多时间去调试并改进。等到后期不断迭代之后,脚本工具会非常成熟,只需要维护表格模板,就可以快速地生成某种格式的手写代码。
举报

更多回帖

发帖
×
20
完善资料,
赚取积分