1.在打开simulink之前要将串口设备打开(一定要注意先后顺序,先打开simulink会导致识别不到串口)
2.simulink模型设置:求解器设置为定步长离散求解器模式
3. simulink仿真的时候会将时间压缩,以降低仿真时长。但对于硬件在环仿真而言,最好使用实时仿真。点击RUN按钮的小三角,点击simulink pacing。在弹出的窗口里选择仿真时间与真实时间的比例为1,即完全模拟真实情况。
4.串口模块配置: 串口配置需要用到三给模块,Serial Configuration、Serial Receive、Serial Send。Serial Configuration用于配置串口参数,Serial Receive、Serial Send分别用于接收和发送串口数据。(instrument Control Toolbox 支持的通讯方式有TCP/IP,UDP,Serial(串口通讯))
4.1 serial configuration:串口配置模块用于配置串口参数用于数据的发送和接收。在设置其他模块前优先设置此模块。
- Communication port:配置串口通讯的端口(此处首先需要保证电脑上有空闲的串口才能选中,可以先用串口调试助手测试,然后在simulink中选择。需要确保串口没有被其他软件占用,不然无法打开)
- Baud rate:设置传输的波特率
- Data bits:设置传输数据为多少位的数据 默认传输8位的数据
- Parity:校验位设置 none-无校验 even-偶校验 odd-奇校验
- Stop bits:停止位
- Byte order:设置数据存储序列的顺序
- little-endian:设备存第一个数据到第一个地址
- big-endian:设备存最后一个数据到第一个地址
- 这个需要参考你控制的,读取的设备是怎么设置的,设备说明书中应该有。匹配起来
- Flow control:管理数据传输速度,决定是否让硬件控制传输的速率(本地方没有弄明白含义)
- Timeout:模型在每个模拟时间步长中等待数据的时间量,在每个仿真步等待数据的最大时间量。
4.2 Serial Receive:串口接收模块配置并开启一个串口通讯端口。在模型执行开始时对配置进行初始化。模块在模型运行时从串口获取数据。串口接收模块采用First in First out (FIFO) buffer先进先出缓存器。
- port:串口通讯的端口。
- Header:(设置数据包包头)通过设置header来让接收模块确认你的数据开始处。当设置header后,header之前的数据simulink会忽略掉。header不会输出到输出口。
- Terminator:(设置数据包包尾)通过设置terminator让接收模块确认你的数据结束处。terninator不会输出到输出口。
- 注:复杂的数据包解析以后用
S-Function
自己写解析函数 - Data size:(接收一次分割接收数据的大小)设置输出的数据大小或者确定在每个仿真步长应当读的数据长度大小。(固定长度数据包)Data size代表数据数量可以是单纯的数字也可以是矩阵形式([2,4])。各数据按从左至右,从上至下的顺序排列。
- Data type :解析数据类型设置,Data type代表数据类型,如single相当于float,占4个字节。单片机发送数据应把所有数据一次性发送出去,数据按上述规则排列,simulink收到后会自动拆分解析为设置的数据类型。
- Block sample time:采样时间。模块在仿真期间的速率。【注意:串口采样频率必须大于等于串口发送频率,不然数据会丢失或卡死】
- Enable blocking mode :是否打开阻塞模式,没有来数据,阻塞
- Enable blocking mode勾选的情况下表示,读取输入数据时暂停其他模块。如果勾选,Serial Receive模块只有一个Output为Data,读取过程大概是这样,从Arduino发出的数据会不停的累积存到电脑缓存区。Serial Receive模块会按照数据进入的顺序读取。因为其他的操作只能在两次采样之间进行,所以这时读取数据不是实时的,而是有延迟的,随着时间延时越来越长。如果不勾选,则有两个Output为Data和Status,status只有两种值1或0,1表示有可用的数据,0表是没有可用的数据。因为不会暂停其他模块,模块意外的操作(模拟)可以看做是连续的,所以现在是实时的。
- 如果仿真很缓慢很可能是串口发送数据长度太长且勾选了阻塞模式
- Action when data is unavailable:没有可读数据时的行为,有两个选项,Output last received value(可理解为输出最后进入缓存的数据)和Output Custom value(输出自定义值,选择该项时,可在下面的Custom Value进行设置,默认为零)。
4.3 Serial Send:从模型中发送数据到串口。可以同时设置多个串口发送模块同时向多个串口发送。串口发送模块发送的模块为输入数据的数值类型。
这个模块比较简单,配置串口和包头包尾即可。根据传输的数据可使用convert模块将数据装换为我们需要的类型,经过转换的数据会全部发送至单片机。我们需要在下位进行数据的拼接和转换(解包)。
demo1:利用串口传输单个数据
uint8_t Rxdata;
uint8_t Txdata; //传输数据缓冲区
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_DMA_Init();
MX_RTC_Init();
MX_USART1_UART_Init();
while (1)
{
HAL_UART_Receive_DMA(&huart1,&Rxdata,1); //接收数据
if(Rxdata>10)
{
Txdata=0;
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1,GPIO_PIN_SET);
}
else
{
Txdata=10;//Ëã·¨
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1,GPIO_PIN_RESET);
}
DMA_HandleTypeDef DMA_Status;
while(HAL_DMA_GetState(&DMA_Status) == HAL_DMA_STATE_BUSY) HAL_Delay(1);
HAL_UART_Transmit_DMA(&huart1,&Txdata,1); //´®¿Ú·¢ËÍ
HAL_Delay(300);
}
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance==USART1)
{
//HAL_UART_Transmit_DMA(&huart1,&Txdata,sizeof(Txdata));
HAL_UART_Receive_DMA(&huart1,&Rxdata,sizeof(Rxdata));
}
}
demo2:串口传输两个double数据
uint8_t Rxdata[16]={0};
double Rx1;
double RX2;
uint8_t Txdata[16]={0};
double Tx1;
double Tx2;
unsigned char * p1;
unsigned char * p2;
int main(void)
{ /* USER CODE BEGIN WHILE */
while (1)
{
HAL_UART_Receive_DMA(&huart1,Rxdata,16); //串口接收,注:数组名即为地址,两个double数据长度为16字节
Rx1=*(double *)&Rxdata[0];
RX2=*(double *)&Rxdata[8]; //数据包解包,将uint8_t Rxdata[16]拆分为两个double
Tx1=RX2; //交换数值
Tx2=Rx1;
p1=(unsigned char *)&Tx1;
p2=(unsigned char *)&Tx2;
for (unsigned char i = 0; i < 8; i++) {
Txdata[i] = *p1;
p1++;
}
for (unsigned char i = 8; i < 16; i++) {
Txdata[i] = *p2;
p2++;
} //打包数据包,将两个double数据打包为uint8_t Txdata[16]
DMA_HandleTypeDef DMA_Status;
while(HAL_DMA_GetState(&DMA_Status) == HAL_DMA_STATE_BUSY) HAL_Delay(1);
HAL_UART_Transmit_DMA(&huart1,Txdata,16); //串口发送
HAL_Delay(300);
/* USER CODE END WHILE */
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance==USART1)
{
//HAL_UART_Transmit_DMA(&huart1,&Txdata,sizeof(Txdata));
HAL_UART_Receive_DMA(&huart1,Rxdata,sizeof(Rxdata));
}
}