📄 uart.c
字号:
#define __UART_H
#include "..\\MAIN\MAIN.H"
#include "..\\ASCHEX\ASCHEX.H"
#include "..\\UART\UART.H"
UARTVALUE idata Uart0;
#define IDLE_WAIT_START 0x00 // 空闲态,等待起始位
#define START_WAIT_END 0X01 // 收到起始位,等待结束位
#define END_WAIT_SEND 0X02 // 收到结束位,等待发送
#define SEND_START_BYTE 0x03 // 发送起始位
#define SEND_WAIT_IDLE 0X04 // 开始发送,等待发送完毕
// 接收中断
void Uart0RxdInterrupt(void) interrupt 4
{
uint8 idata temp;
if(RI)
{
RI = 0;
temp = SBUF;
switch( Uart0.Status )
{
case IDLE_WAIT_START:
if( temp == ':' ) // 收到起始位
{
Uart0.Status = START_WAIT_END; //状态切换
Uart0.Point = 0;
}
break;
case START_WAIT_END:
if( temp == ':' ) //如果再次收到起始位,则重新开始接收
{
Uart0.Point = 0;
}
else
{
if( (temp == 0x0a) && (Uart0.Pool[Uart0.Point-1]==0x0d) )
{//判断结束位
Uart0.Pool[Uart0.Point] = temp;
Uart0.RxdLen = Uart0.Point;
Uart0.Status = END_WAIT_SEND; //状态切换
}
else
{
Uart0.Pool[Uart0.Point] = temp;
Uart0.Point++;
Uart0.Point %= 100;
}
}
break;
case END_WAIT_SEND:
case SEND_WAIT_IDLE:
default:
break;
}
}
}
// 发送中断
void Uart0TxdInterrupt(void) interrupt 13
{
if( TI )
{
TI = 0;
if( Uart0.TxdLen > 0 )
{
SBUF = Uart0.Pool[Uart0.Point];
Uart0.TxdLen--;
Uart0.Point++;
Uart0.Point %= 100;
}
else
{ //发送完毕
Uart0.Status = IDLE_WAIT_START; //状态切换
}
}
}
void UARTInit(void)
{
uint8 idata i;
SCON = 0x50; // 使能接收,串口模式1
SSTAT = 0x20; // 选择独立的RX/TX中断,禁止双缓冲
BRGR0 = 0xF0; //
BRGR1 = 0x02; // 独立的波特率发生器的值,7.373M晶振时波特率为 9600
BRGCON = 0x03; // 使能独立的波特率发生器
ESR = 1; // 开启接收中断
EST = 1; // 禁止发送中断
RS485EN = 0; // 关闭 RS485 发送使能
Uart0.Addr = GetAddr(); // 获取本机地址,允许带电更改本机地址,由硬件拨码开关决定
for( i = 0;i < 100;i++ )
{
Uart0.Pool[i] = 0;
}
Uart0.TxdLen = 0;
Uart0.RxdLen = 0;
Uart0.Point = 0;
Uart0.Status = IDLE_WAIT_START;
}
void UartProcess(void)
{
uint8 idata LrcData;
uint8 idata Addr,FunCode;
uint16 idata RegAddr,RegNum;
uint16 idata ybuf[15];
uint8 idata i,temp;
switch( Uart0.Status )
{
case END_WAIT_SEND: //处于解码状态
asc_to_hex(Uart0.RxdLen - 2); //解包
LrcData = Uart0.Pool[(Uart0.RxdLen - 2) / 2 - 1];
if( LrcData == LRC8((Uart0.RxdLen - 2) / 2 - 1) )
{
LrcData = 1;
}
else
{
LrcData = 0;
}
//DEBUG用
// LrcData = 1;
//DEBUG用
if( LrcData == 1 ) //如果校验正确才继续 解码
{
Addr = Uart0.Pool[0]; //获得地址
if( Addr == Uart0.Addr ) //地址判断,正确才应答处理
{
FunCode = Uart0.Pool[1]; //获得功能码
RegAddr = ((Uart0.Pool[2] - (uint8)Uart0.Addr) << 8) + Uart0.Pool[3];
// 计算 寄存器首地址
RegNum = (Uart0.Pool[4]<<8) + Uart0.Pool[5];
// 计算 寄存器数量
switch( FunCode )
{
case 0x03: // 读保持寄存器值。暂时不写 0x03命令对应的功能。
break;
case 0x04: // 读取输入寄存器的值
if( (RegNum>0) && (RegNum<13) && ( (RegAddr + RegNum)<13 ) && (RegAddr < 12) )
{
for( i = 0;i < RegNum;i++ ) //
{
ybuf[i] = Reg.wreg[RegAddr+i]; //
}
MsReadAnswer(FunCode,i,ybuf); // 读 输入寄存器 回答
}
else
{
ExcepAnswer(FunCode|0x80,0x03); // 回答 读地址错误
}
break;
case 0x10: //
if( (RegNum*2) == Uart0.Pool[6] ) // 写字节数和参数长度是否配套
{
if( (RegNum==1) && (RegAddr==0x0b ) )
{ // 判断寄存器首地址和寄存器长度是否正确
temp = 7;
for( i = 0;i < RegNum;i++ )
{ // 注意大端小端,51系列单片机是大端模式,高字节数据放低地址
Reg.breg[ (RegAddr + i) * 2 + 0 ] = Uart0.Pool[temp++];
Reg.breg[ (RegAddr + i) * 2 + 1 ] = Uart0.Pool[temp++];
}
Flag.DaOutNew = 1;
MsWriteAnswer(FunCode,RegAddr,RegNum);
// 回答写地址 命令
}
else
{ // 如果地址错误
ExcepAnswer(0x90,0x03); // 回答写地址错误
}
}
else
{
ExcepAnswer(0x90,0x02); // 非法长度
}
break;
default:
ExcepAnswer(FunCode|0x80,0x01); // 回答功能码错误
break;
}
Uart0.Status = SEND_START_BYTE; // 发送起始位状态
}
else //地址不对返回接收等待起始位状态
{
Uart0.Status = IDLE_WAIT_START;
}
}
else //校验出错返回接收等地啊起始位状态
{
Uart0.Status = IDLE_WAIT_START;
}
break;
case IDLE_WAIT_START: //发送完毕等待开始位状态
//对RS485总线需要操作
RS485EN = 0;
//DEBUG
// ChangeLed(0);
//DEBUG
break;
case SEND_START_BYTE: //发送起始位状态,对总线有操作
RS485EN = 1; //使能发送控制
Uart0.Point = 0;
TI = 0;
SBUF = 0x3a;
Uart0.Status = SEND_WAIT_IDLE; //发送状态,等待发送结束
break;
case START_WAIT_END:
case SEND_WAIT_IDLE:
break;
default:
break;
}
}
/****************************************************************************
*
****************************************************************************/
uint8 LRC8(uint8 idata usDataLen)
{
uint8 idata uchLRC = 0; //
uint8 idata i;
for( i = 0;i < usDataLen;i++ )
{
uchLRC += Uart0.Pool[i]; //
}
return( (uint8)(-((char)uchLRC)) ); //
}
void MsReadAnswer(uint8 fun_code,uint16 reg_num,uint16 *data_buf)
{
uint8 i,j;
Uart0.Pool[0] = (uint8)(Uart0.Addr); //
Uart0.Pool[1] = fun_code; //
Uart0.Pool[2] = (uint8)(reg_num*2); //
i = 3;
for(j=0;j<reg_num;j++) // 这里转换的时候注意芯片的大端模式和小端模式的区别
{ // 一般而言,51系列单片机是大端模式,飞利浦的ARM是小端模式
Uart0.Pool[i] = (uint8)((*(data_buf+j)>>8)&0x00ff);
// 高字节数据放低地址
i++;
Uart0.Pool[i] = (uint8)(*(data_buf+j)&0x00ff); // 低字节数据放高地址
i++;
}
Uart0.Pool[i] = LRC8(i); //
hex_to_asc(i+1); //
}
void ExcepAnswer(uint8 FunCode,uint8 ExcepCode)
{
Uart0.Pool[0] = (uint8)(Uart0.Addr); //
Uart0.Pool[1] = FunCode; //
Uart0.Pool[2] = ExcepCode; //
Uart0.Pool[3] = LRC8(3); //
hex_to_asc(4); //
}
void MsWriteAnswer(uint8 fun_code,uint16 reg_addr,uint16 reg_num)
{
Uart0.Pool[0] = (uint8)(Uart0.Addr); //
Uart0.Pool[1] = fun_code; //
Uart0.Pool[2] = (uint8)(Uart0.Addr); //
Uart0.Pool[3] = (uint8)( (reg_addr) & 0x00ff ); //
Uart0.Pool[4] = (uint8)((reg_num>>8) & 0x00ff ); //
Uart0.Pool[5] = (uint8)(reg_num & 0x00ff); //
Uart0.Pool[6] = LRC8(6); //
hex_to_asc(7); //
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -