📄 rs485.c
字号:
/********************************************************************************
*
*
*名称:master.c
*功能:RS485主机收发程序
*说明:主机向整个网络发送地址信息,等待接收从机数据包
*程序设计:
*设计时间:
*
*
通信规则:
1:时钟4MHZ/波特率9600bps
2:通讯连接采用硬件MAX485,双向半双工
3:采用一主多从的多机通信方式
4:主机数据包格式,帧头+从机地址 + CRC8校验位
5:从机数据包格式,帧头+主机地址 + 从机地址 + 数据长度 + 数据块 + CRC8校验位
6:主机向整个网络发送数据包,等待从机的反应
7:所有从机处于接收状态,当接收到的数据包中的地址信息与本机匹配,立即给主机发送数据
否则从机继续处于接收状态
8:当主机接收到从机信息判断是否是要访问的从机,是则保存相应的温度数据,并发送下一个
从机地址信息,否则主机再次发送该从机地址信息访问该从机
9:发送数据包采用查询方式,接收数据包采用中断方式
10:0为无效地址,主机地址是1,从机地址是2.3.4......
*
*
*********************************************************************************/
#include <pic18.h>
#include "rs485.h"
unsigned char h;
unsigned char i;
typedef struct{ //结构体定义每个箱子的温度数据
unsigned char box_num; //箱子号
unsigned char tempeture[NumOfChannel]; //六路温度数据
}wendu;
wendu box[NumOfBox]; //定义3个探测箱数据结构
const unsigned char SlaveAddr[] = {2,3,4,5,6,7,8,9,10,11}; //3个从机地址
unsigned char SendBuf[LenOfSend]; //发送数据缓冲区
unsigned char RecBuf[LenOfRec]; //接收数据缓冲区
unsigned char REC_BUF[60];
//static unsigned char Start; //接收数据起始位
//定时时间到,则设置开始发送数据包
//static unsigned char start_send_flag = 0; //开始发送数据标志
unsigned char flag_me; //本机数据标志
unsigned char rec_count = 0; //接收计数
static unsigned char j;
extern void ClearLcd( void );
/*
********************************
*
*名称:
*功能:
*说明:
*参数:
*
********************************
*/
void Timer1Init( void )
{
GIE = 0; //关全局中断
TMR1IF = 0;
TMR1H = 0XC3;
TMR1L = 0XB0; //4M外部晶振,定时器赋初值50000,0.1s定时
T1CON = 0x10; //开启定时器1,定时模式8分频,指令周期2us
TMR1IE = 1; //开启定时器1中断
PEIE = 1; //开启外围中断
TMR1ON = 1; //开启定时器Timer1
GIE = 1; //全局中断允许
}
//Usart串口初始化函数
void UsartInit( void )
{
GIE = 0; //关闭全局中断
TRISC7 = 1; //RX(RC7引脚)为输入
TRISC6 = 0; //TX(RC6引脚)为输出
TRISC2 = 0; //RC2作为MAX485控制位,输出
RC2 = 0; //单片机上电主机处于接收状态
CSRC = 0; //选择外部时钟
SPBRG = 25; //外部晶振4MHZ,波特率设定9600bps
// SPBRG = 103; //外部晶振4MHZ,波特率设定2400bps
BRGH = 1; //高速模式
SYNC = 0; //异步通信
SPEN = 1; //打开串行通信口
TX9 = 0; //选择8位数据发送
RX9 = 0; //选择8位接收
TXIF = 0; //不受软件控制
TXEN = 1; //发送使能
RCIE = 1; //接收中断使能
RCIF = 0; //不受软件控制
CREN = 1; //允许连续接收
PEIE = 1; //外部中断使能
GIE = 1; //开全局中断
}
/********************************
*名称:
*功能:1us延时函数
*说明:
*参数:
*返回值:
*********************************/
void delay_1us( void )
{
asm( "nop" );
}
/********************************
*名称:
*功能:N us延时函数
*说明:
*参数:
*返回值:
*********************************/
void delay_nus( unsigned int n )
{
unsigned int i=0;
for( i = 0; i < n; i++ )
delay_1us();
}
/********************************
*名称:
*功能:
*说明:
*参数:
*返回值:
*********************************/
void delay_1ms()
{
unsigned int i;
for( i = 0; i < 1140; i++ )
;
}
/********************************
*名称:
*功能:
*说明:
*参数:
*返回值:
*********************************/
void delay_nms( unsigned int n ) //N ms延时函数
{
unsigned int i = 0;
for (i = 0; i < n; i++ )
delay_1ms();
}
/********************************
*名称:
*功能:CRC8校验
*说明:
*参数:
*返回值:
*********************************/
unsigned char crc8(unsigned char *ptr, unsigned char len)
{
unsigned char i;
unsigned char crc = 0;
while( ( len-- ) != 0 )
{
for( i = 1; i != 0; i *= 2 )
{
if( ( crc & 1 ) != 0 )
{
crc /= 2;
crc ^= 0x8C;
}
else
crc /= 2;
if( ( *ptr & i ) != 0 )
crc ^= 0x8C;
}
ptr++;
}
return( crc );
}
/********************************
*名称:
*功能:发送len个字节
*说明:
*参数:
*返回值:
*********************************/
void SendData( unsigned char *data, unsigned char len)
{
unsigned char i = 0;
UsartConBit = 1; //Usart口处于发送状态
while( i < len )
{
TXREG = data[i];
while( TXIF == 0 ); //等待发送完成,TXREG为空时TXIF=1
i++; //发送次数统计
delay_nms(10); //每次发送数据之间有间隔
}
UsartConBit = 0; //数据发送完后处于接收状态
}
/********************************
*名称:
*功能:
*说明:
*参数:
*返回值:
*********************************/
void Rs485SendPkg( unsigned char address )
{
RCIE = 0; //关闭接收中断
TXEN = 1; //允许发送
//将待发送的数据加载到发送缓冲区
SendBuf[0] = 0x55; //帧头
SendBuf[1] = address; //从机地址信息
SendBuf[LenOfSend - 1] = crc8( SendBuf,LenOfSend - 1 ); //校验位
//Print( SendBuf );
SendData( SendBuf,LenOfSend ); //发送数据
delay_nms(10);
//主机发送完数据后
RCIE = 1; //打开接收中断
CREN = 1; //允许连续接收
}
/********************************
*名称:
*功能:
*说明:
*参数:
*返回值:
*********************************/
void Rs485_master( unsigned char j )
{
unsigned char crc8_check;
unsigned char h;
unsigned char i;
// for( j = 0; j < ( sizeof(SlaveAddr) / sizeof(unsigned char) ); j++)
{
Rs485SendPkg( SlaveAddr[j] ); //发送数据包
UsartConBit = 0;
RCIE = 1;
CREN = 1;
delay_nms(50);
//收发状态转换之间间隔不能太长
while(1)
{
//等待中断
if( flag_me == 1 )
{
flag_me = 0; //标志位清零
// Print("hello");
//Print( RecBuf );
if( RecBuf[2] == SlaveAddr[j] )
{
//Print("hello");
crc8_check = crc8( RecBuf, LenOfRec - 1 );
if( crc8_check == RecBuf[LenOfRec - 1] )
{
//接收到的数据校验正确
rec_count = 0; //接收计数清零
for( h = 0; h < NumOfChannel; h++ )
{
box[j].tempeture[h] = RecBuf[h+4]; //存储温度数据到相应箱子结构体中
REC_BUF[h+j*6] = box[j].tempeture[h];
//TRISD = 0x00;
//PORTD = box[j].tempeture[h];
//delay_nms(10);
}
// Print("microchip");
// GotoXY(2,8);
// ClearLcd(); //清屏
// GotoXY(1,0);
// Print( j+1 );
// GotoXY(2,0);
// Print( box[j].tempeture ); //显示接收到的数据
break; //接收成功,跳出while死循环,访问下一个从机
}
else
{
// Print("hello");
//接收数据错误
rec_count = 0; //接收计数清零
//Rs485SendPkg( SlaveAddr[j] ); //重新访问该从机
//break;
//while()//发送次数计数
}
}
}
else
{
//Print("hello");
rec_count = 0;
break;
}
}
//Print("world");
// break;
}
}
////////////////////////////////////////////////
/*if( ten_minute == set_ten_minute )
{
ten_minute = 0;
flash_falg = 1;
}
*/
////////////////////////////////////////////////
/*
/////////////////////////////////////////////
////////////// 主函数 ////////////////////
/////////////////////////////////////////////
void main( void )
{
UsartInit(); //初始化
Timer1Init(); //Timer1初始化
InitLcd(); //LCD初始化
while(1)
{
if( ten_minute > set_ten_minute )
{
ten_minute = 0; //十分钟计数清零
//到了定时时间,set_ten_minute个十分钟
Rs485_master(); //开始收发数据
}
}
}
*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -