将汇编翻译成C了, 累死了。。。
应项目要求靠着一个汇编写的自定义协议源代码 硬是用C 实现。。。头大了。。// 模块功能: 实现STM32与PIC16F57串行通信。
#include "PIC16F57_CM.h"
#include "Delay.h"
/*******************************************相关宏定义*****************************************/
#define SERIAL_TIME 530
#define SERIAL_TIME_BASE 10 // 0.5S
#define SWAP(A) ((A >> 4 | A << 4) & 0xff)
/*******************************************相关函数定义***************************************/
u8 Serial_Read(u16 *);
u8 Serial_Read_ASK(void);
u8 Serial_Write(u16 );
u8 Serial_Write_ASK (void);
void Serial_Free_IO(void);
void Serial_Func (void);
void Serial_Write_ACK(void);
u8 Serial_Read_ACK(void);
u8 Serial_Write_Task (u16 );
u8 Serial_Read_Task (u8 * , u8 * );
u8 Serial_UnlockCode (u16 , u8 *, u8 * );
/*******************************************相关全局变量定义***************************************/
u16 Serial_Write_Data; /* 待写数据 */
u8 Serial_Read_Data; /* 经解码后的有效数据 */
u8 Write_Enable; /* 需要写操作 */
u8 Serial_Write_Time;
u8 Serial_Read_Data_Type;
/* *******************************************************************************************************
* 函数功能: STM32 与 PIC 通信入口
*
* 参数: Has_Police_Flag == true: 需要写操作
* Serial_Send_Time: 写操作间隔时间
*
* 备注: 读写数据操作的前提是需要判断SDA SCL管脚的电平状态:
* 1、当SDA管脚处于低电平状态时则可以执行读操作。
* 2、当SDA和SCL同时空闲(高电平)则可以执行写操作。
*
*********************************************************************************************************/
void Serial_Func (void)
{
if (READ_SERIAL_SDA)
{
if ( READ_SERIAL_SCL && Write_Enable && Serial_Write_Time > SERIAL_TIME_BASE)
{
static u8 Serial_Fault_Counter = 0; /* 故障计数器 */
Serial_Write_Time = 0; /* 清除发送间隔时间 */
if (Serial_Write_Task (Serial_Write_Data))
{
Write_Enable = 0; /* 操作成功,失能写操作 */
Serial_Fault_Counter = 0; /* 执行成功清故障计数器 */
}
else
{
Serial_Fault_Counter++; /* 发送失败则标记 */
if (Serial_Fault_Counter > 10)
{
Serial_Fault_Counter = 0;
Write_Enable = 0 ;
Serial_Write_Data = 0;/* 超过指定次数则销毁待发数据 */
}
}
Serial_Free_IO(); /* 执行完读写操作则释放总线 */
}
}
else
{
u8 data = 0, Type = 0;
if (Serial_Read_Task (&data, &Type))
{
Serial_Read_Data = data;
Serial_Read_Data_Type = Type;
}
Serial_Free_IO(); /* 执行完读写操作则释放总线 */
}
}
u8 Serial_Write_Task (u16 Data)
{
if (Serial_Write_ASK ())
{
/* 握手成功 */
SERIAL_SCL_OUT();
if ( Serial_Write (Data) )
return 1;
}
return 0;
}
/*
* 函数功能:读数据
*
* 参数: data: 成功读操作后保存有效数据
* Type: 读到的数据类型
*
* 备注:
*
*/
u8 Serial_Read_Task (u8 * pData, u8 * pType)
{
u8 Type = 0;
u8 Valid_Data = 0;
u16 Pack_Data = 0;
if ( Serial_Read_ASK () ) /* 读起始信号 */
if ( Serial_Read (&Pack_Data) ) /* 读数据 */
if ( Serial_UnlockCode (Pack_Data, &Valid_Data, &Type) ) /* 解码 */
{
*pData = Valid_Data; /* 数据有效*/
*pType = Type;
Serial_Write_ACK(); /* 发送应答信号 */
return 1; /*读操作成功 */
}
return 0; /* 读操作失败 */
}
/*
* 函数功能:初始化串行通信管脚
*
*
* 备注:
*
*/
void Serial_Init (void)
{
RCC_APB2PeriphClockCmd ( RCC_APB2Periph_GPIOB, ENABLE);
SERIAL_SCL_IN(); /* 输入上拉 */
SERIAL_SCL_IN(); /* 输入上拉 */
}
/*
* 函数功能:释放通信管脚
*
*
* 备注: 管脚属性为输入上拉
*
*/
void Serial_Free_IO(void)
{
SERIAL_SDA_IN();
SERIAL_SCL_IN();
}
/*
* 函数功能:通信写握手操作
*
* 返回: 1:成功 0:失败
*
*
*/
u8 Serial_Write_ASK (void)
{
SERIAL_SDA_OUT();
SERIAL_SDA_L;
delay_us(SERIAL_TIME);
if (!READ_SERIAL_SCL)
{
SERIAL_SDA_H;
delay_us(SERIAL_TIME);
if (READ_SERIAL_SCL)
return 1;
}
return 0;
}
/*
* 函数功能:写数据操作
*
* 返回: 1:成功 0:失败
*
* 备注:
*/
u8 Serial_Write(u16 Data)
{
u16 i;
for (i = 0; i < 16; i++)
{
SERIAL_SCL_L;
if ( Data & 0x8000)
SERIAL_SDA_H;
else
SERIAL_SDA_L;
Data <<= 1;
delay_us(SERIAL_TIME);
SERIAL_SCL_H;
delay_us(SERIAL_TIME);
}
Serial_Free_IO();
return Serial_Read_ACK();
}
/*
* 函数功能:读ACK信号
*
* 返回: 1:应答成功 0:应答失败
*
* 备注:
*/
u8 Serial_Read_ACK(void)
{
u16 i = 1800;
while ( i-- )
{
delay_us (1);
if (!READ_SERIAL_SCL)
return 1; /* 收到对方应答发送成功 */
}
return 0;
}
/*
* 函数功能:通信读握手操作
*
* 返回: 1:成功 0:失败
*
*
*/
u8 Serial_Read_ASK(void)
{
if ( !READ_SERIAL_SDA )
{
SERIAL_SCL_OUT();
SERIAL_SCL_L;
delay_us(SERIAL_TIME);
if (READ_SERIAL_SDA) /* 等待释放总线命令 */
{
SERIAL_SCL_IN(); /* 释放总线 */
delay_us(SERIAL_TIME); /* 间隔530us准备读取数据 */
return 1;
}
}
return 0;
}
/*
* 函数功能:写ACK信号
*
* 返回:
*
*
*/
void Serial_Write_ACK(void)
{
SERIAL_SCL_OUT();
SERIAL_SCL_L;
delay_us(SERIAL_TIME);
}
/*
* 函数功能:读数据操作
*
* 返回: 1:完整数据 0:残缺数据
*
*
*/
u8 Serial_Read(u16 *pData)
{
u8 Out_Timer = 0;
while (1)
{
/* 从释放总线到 接收第一个数据此时间隔530us */
if ( !READ_SERIAL_SCL)
{
HI:
delay_us(SERIAL_TIME);
if (READ_SERIAL_SCL)
{
Out_Timer = 0;
*pData <<= 1;
if (READ_SERIAL_SDA)
*pData |= 0x0001;
delay_us(SERIAL_TIME);
}
else
{
/* 低电平超时 */
Out_Timer++;
if (Out_Timer > 1)
return 0;
goto HI;
}
}
else
{
Out_Timer++;
if (Out_Timer > 1)
return 1; /* 高电平持续超过1ms,接收完成。*/
delay_us(SERIAL_TIME);
}
}
}
/*
* 函数功能:对待发数据编码
*
* 参数 Type: 数据类型, 为0表示正常数据 为其他值表示保留数据。
* Data: 待编码数据。
*
* 返回: 编码后的待发数据
*
*/
u16 Serial_Coding(u8 Type, u8 Data)
{
u8 Data_Tmp;
static u8 Serial_Number = 0; //流水号
/*组装类别状态字,各位属性如下:
bit<7,6> = 00 - 正常
bit.1 - 隐蔽报警
bit.0 - 流水号(每次发送变化一次)
*/
Type <<= 6;
Type |= !Serial_Number;
/*组装信号/校验和字节:信号/校验和字的字宽为一个字节,它其实是将待发数据编码,保证接收方能验证数据的完整性。假设TYPE是类别状态字、DATA是有效数据(低四位有效)、WORK是信号/校验和字节,则分以下步骤完成编码:
1、Data_Tmp = Data。
2、取Type 高低位交换值
3、DATA = DATA + TYPE + (TYPE高低位交换的值)。
4、将WORK舍弃高四位,低四位移到高四位。将DATA 的低四位按照降序存入到 WORK的低四位。比如 原先 DATA的BIT3 最后位于WORK的BIT0。
*/
Data_Tmp = Data;
Data += Type + SWAP(Type);
Data_Tmp <<= 4;
Data_Tmp |= (Data & 0x01) << 3 | (Data & 0x02) << 1 | (Data & 0x04) >> 1 | (Data & 0x08) >> 3;
return 256 * Type + Data_Tmp;
}
/*
* 函数功能:解码读到的数据
*
* 参数 Input_Data: 读到的数据
* pData:解码后的数据
* pType: 解码后的数据类型(警情或者拨码盘编码)
*
* 备注:
*/
u8 Serial_UnlockCode (u16 Input_Data, u8 *pData, u8 * pType)
{
u8 Data_H = 0;
u8 Data_L = 0;
u8 Data_L_Tmp = 0;
/* 分离高低字节 */
Data_L = Input_Data & 0x00ff;
Data_H = Input_Data >> 8;
/* 备份低字节数据 */
Data_L_Tmp = Data_L;
/*
Data_L = Data_L高低位交换值 + Data_H高低位交换值 + ata_H
*/
Data_L = SWAP(Data_L) + SWAP(Data_H) + Data_H;
/*
* Data_L_Tmp 低四位升序移入 Data_L的低四位 比如Data_L_Tmp的bit0 移到Data_L的bit3
*/
Data_L <<= 4;
Data_L |= (Data_L_Tmp & 0x01) << 3 | (Data_L_Tmp & 0x02) \
<< 1 | (Data_L_Tmp & 0x04) >> 1 | (Data_L_Tmp & 0x08) >> 3;
/* 校验数据 */
if ( SWAP(Data_L) == Data_L )
{
*pData = Data_L_Tmp >> 4;
*pType = Data_H & 0xc0; /*[类别]:00 - 正常,01 - 保留,10 - 拨号手柄,11 - 车载手柄 */
return 1;
}
return 0;
}