{
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)含义为取得该地址内的数据;
上一篇:MMC中断的特点及解决方案
下一篇:SAR ADC内部结构
推荐阅读最新更新时间:2024-11-14 09:32
设计资源 培训 开发板 精华推荐
- 使用 NXP Semiconductors 的 MC68HC908KX8 的参考设计
- LTC3830EGN 演示板、高效降压电源、3V 至 8V 输入、2.5/1.8/1.5Vout @ 15A
- 首次创建
- 用于笔记本电脑的 MOSFET 功率驱动器
- 使用 Cypress Semiconductor 的 CYPD1103-35FNXI 的参考设计
- LTC2945IUD 宽范围 -4V 至 -500V 负功率监视器的典型应用
- 使用 Infineon Technologies AG 的 OM7585AST 的参考设计
- FAN2306 微型降压 6A 集成同步降压稳压器的典型应用
- SOT-23 SMBU 风扇速度控制器设计可延长电池寿命并降低噪音
- 使用 Analog Devices 的 ADP224ACPZ 的参考设计