调试工具:Modbus Poll
编程软件:Atmel Studio 7
理解:PC中的Modbus Poll是主机,而AVR芯片作为从机
此处有两种串行传输模式:RTU和ASCII
此处使用了RTU模式,这种模式的主要优点是较高的数据密度,在相同的波特率下比ASCII 模式有更高的吞吐率。每个报文必须以连续的字符流传送。
//以下是必要的函数
void usart_init(uint baud)//波特率
{
UCSRA = 0X00;
UCSRB = 0X00;
UCSRC = 0X86;// 访问UCSRC 异步 奇偶禁止 停止位1位 字符8位
baud = fosk/16/baud-1;//得到UBRR
UBRRL=baud;
UBRRH=baud>>8;
UCSRB=(1<
SREG|=(1<<7);//全局中断开放
DDRD|=(1<<1);//PD1 TXD配置为输出模式
}
void usart_send(uchar *buf,uchar len)
{
while(len--)//发送所有字节
{ //等待发送缓冲器为空
while(!(UCSRA&((1<
UDR=*buf++;//发送一个字节数据
}
}
uchar usart_read(uchar *buf, uchar len)
{
uchar i;
if (len > cntRxd) //指定读取长度大于实际接收到的数据长度时,
{ //读取长度设置为实际接收到的数据长度
len = cntRxd;
}
for (i=0; i
{
*buf++ = bufRxd[i];
}
cntRxd = 0; //接收计数器清零
return len; //返回实际读取长度
}
void UartRxMonitor(uchar ms)//定时器1发生一次中断则进入一次该函数(记得放入定时器的中断函数)
{
static uchar cntbkp = 0;
static uchar idletmr = 0;
if (cntRxd > 0) //usart中断发生后,接收到数据,接收计数器大于零时,监控总线空闲时间
{
if (cntbkp != cntRxd) //接收计数器改变,即刚接收到数据时,清零空闲计时
{
cntbkp = cntRxd;
idletmr = 0;//清空空闲计时
}
else //接收计数器未改变,即总线空闲时,累积空闲时间
{
if (idletmr < 22) //1/19200*3.5*10
{
idletmr += ms;
if (idletmr >= 22) //判定一帧接收完毕
{
flagFrame = 1; //设置帧接收完成标志
}
}
}
}
else
{
cntbkp = 0;
}
}
void usart_driver()//此函数放入while(1)中(该函数网上有)
{
关键点需要按照自己的写,记得收和发都需要经过CRC校验(网上有现成程序crc16.c);
Modbus poll一发指令,就会触发ISR (USART_RXC_vect)函数,把指令放入bufRxd[];
等到flagFrame=1,启动usart_read()函数,把指令读到AVR;
把AVR采样得到的数放入数组,发指令的时候;
比如:发指令 01 04 00 00 00 01 31 CA // 设备地址01 功能码04 寄存器地址0 读取1个
响应就是 01 04 02 00 0E 38 F4 //设备地址01 功能码04 字节数2 高字节00 低字节0E
//采样数值数码管显示为14,对应了0X0E
AVR采样得到的数值发回给PC机,并在Modbus poll上显示出来;
}
ISR (USART_RXC_vect)
{
if (cntRxd < sizeof(bufRxd)) //接收缓冲区尚未用完 bufRxd[]是char类型
{
bufRxd[cntRxd++] = UDR;
}
}
『本文转载自网络,版权归原作者所有,如有侵权请联系删除』