搜索
bottom↓
回复: 18

转)RS485多机通信程序(终结版AVR)

[复制链接]

出0入0汤圆

发表于 2012-3-25 16:01:40 | 显示全部楼层 |阅读模式
.
RS485多机通信程序(终结版AVR)

RS485多机通信程序(终结版AVR)  


单片机:AVR ATMEGA8
通信:RS485
芯片:MAX485/MAX487
要求:一个主机从机三个以上。(本例使用3个从机)
工作原理:
三个从机:
采集电压(1-5V),并把数据发给主机
模数采样引脚PC0/ADC0
MAX487的RE和DE连在一起,并接到PD3
主机:
MAX487的RE和DE连在一起,并接到PD3
PC0-PC3接1602液晶的D4-D7 (只用4条数据线)
PD7接LCD  E
PC4接LCD  RW
PC5接LCD  RS
工作过程:
从机等间隔进行进行AD采样
1. 主机发送地址(adr):01 寻找01从机 ,01号从机收到后,把AD采回来的数据发给主机,主机把数

据显示在LCD上。
2. 从机改变发送02 找2号从机,重复步骤1。完了再发03。这样轮换的通信。
程序在实际硬件上已经调试成功,验证了正确性,下面把程序贴出来供大家参考。
采用9位数据帧
下面是程序,使用ICCAVR软件编写
主机程序:
#include
#include
#pragma interrupt_handler uartrupt:12
unsigned char temp; //接收临时变量
unsigned char adr;  //从机地址及标志位
const unsigned char LCD[]="IP01 IP02 IP03";
const unsigned char LCDASC[]={0X30,0X31,0X32,0X33,0X34,0X35,0x36,0x37,0x38,0x39};
unsigned char LCDA=0;
unsigned char LCDB=0;
unsigned char LCDC=0;
//QQQQQQQQQQQQQQQQQQQ
//名称:Delay()
//功能:延时程序
//QQQQQQQQQQQQQQQQQQQ

void Delay(int t)
{
while(t--);
   
}
void LDelay(int t)//延时程序(时间较长)
{
for(;t>0;t--)
{
  Delay(4000);
}
   
}


//*************************************
//名称:LCDCOM()与LCDTATA()LCDinit()
//功能:1602液晶显示
//*************************************
void LCDCOM(unsigned char com)
{
unsigned char tempcom;
tempcom = com;
DDRC |=0X3F; //PORTC0-5 OUTPUT
DDRD |=0X80;//pd7 output
PORTC &=~0x20; //RS = 0
com = com>>4;
com =com&0x0f;
PORTC &=0XF0; //低4位清零
Delay(100);
PORTC |=com;//写指令
Delay(100);
PORTD|=0x80; //EN
Delay(100);
PORTD&=~0x80;
//LLLLLLLLLLL
com = tempcom&0x0f;
PORTC &=0XF0; //清零
Delay(100);
PORTC |=com;//写指令
Delay(200);
PORTD|=0x80; //EN
Delay(100);
PORTD&=~0x80;

}
void LCDTATA(unsigned char tata)
{
unsigned char temptata;
temptata = tata;
DDRC |=0X3F;
DDRD |=0X80;//pd7 output
PORTC|=0x20; //RS = 1
tata= tata>>4;
tata &= 0x0f;
PORTC &=0XF0; //清零
Delay(100);
PORTC |=tata;//写指令
Delay(100);
PORTD|=0x80; //EN
Delay(100);
PORTD&=~0x80;
//LLLLLLLLLLL
tata = temptata&0x0f;
PORTC &=0XF0; //清零
Delay(100);
PORTC |=tata;//写指令
Delay(100);
PORTD|=0x80; //EN
Delay(100);
PORTD&=~0x80;
}
void LCDinit()
{
LCDCOM(0X28);
Delay(3000);
LCDCOM(0X28);
Delay(3000);
LCDCOM(0X28);
Delay(3000);
LCDCOM(0X28);
Delay(3000);  //while(t--) Delay(3000)以上
LCDCOM(0X08);
Delay(3000);
LCDCOM(0X01);
Delay(3000);
LCDCOM(0X06);
Delay(3000);
LCDCOM(0X0c);
Delay(3000);
LCDCOM(0x01);//清屏

}

//======================
//名称:USARTinit()
//功能:串行通信初始化,设置引脚功能,波特率,通信方式
//波特率=fosc/16(ubrr+1)
//======================
void USARTinit()
{
UBRRL=25; //波特率2400 //UCSRA 正常波特率
//UBRRH=0x00;
UCSRA=0X0;
UCSRB=0X0;
//UCSRA=RXC|TXC|UDRE|FE|DOR|PE|U2X|MPCM(10100001)
UCSRA=0X0;//接收数据  
//UCSRC=URSEL|UMSEL|UPM1|UPM0|USBS|UCSZ1|UCSZ0|UCPOL
UCSRC|=0x86 ;     //设置数据位
//UCSRB=RXCIE|TXCIE\UDRIE|RXEN|TXEN|UCSZ2|RXB8|TXB8(10011000)
UCSRB=0X9c; //引脚功能设为TXD与RXD,发送地址//UCSZ2=1即9位数据

MCUCR|=0x00; // 开中断(MCU控制寄存器)
GICR=0x00;   ////通用中断控制器
TIMSK=0x00;  //定时计数据中断屏蔽寄存器
//总中断必须是最后使能
SREG|=0x80;  //开中断
}


//========================
//名称:发送地址函数
//功能:寻找从机
//========================
void SEND(unsigned char mydata)
{
DDRD|=0X08; //MAX485允许输出
PORTD|=0X08;
UCSRB|=0x01; //TXB8=0发地址
Delay(1000);
while(!UDRE);
UDR=mydata;
Delay(1000); //必有
PORTD&=~0X08; //发送后立即转为接收等从机发来数据
  
}
//==分解数
void TOLCD(unsigned char LCDP) //发送变量数据给LCD
{   
   
  LCDA=LCDP/100;
  LCDA=(int)LCDA;
  LCDB=(LCDP%100)/10;
  LCDB=(int)LCDB;
  LCDC=(LCDP%100)%10;
  LCDC=(int)LCDC;
  LCDTATA(LCDASC[LCDA]);
  LCDTATA(LCDASC[LCDB]);
  LCDTATA(LCDASC[LCDC]);
}
//======================
//名称:接收中断
//功能:接收数据
//======================
void uartrupt()
{  
  temp=UDR; //读数据
//第一行显示:IP01 IP02 IP03
//各从机数据在LCD的第二行,不同位置显示
//IP01 IP02 IP03
//1.2V 2.3V 3.6V
//显示如上,控制显示位置是下面这几句:
if(adr==1){LCDCOM(0xc0);TOLCD(temp); }  
if(adr==2){LCDCOM(0xc0+5);TOLCD(temp);}
if(adr==3){LCDCOM(0xc0+10);TOLCD(temp);}

}


//======================
//名称:主函数
//======================
void main()
{unsigned char str;
DDRD|=0X08;   //MAX485允许输出
PORTD|=0X08;
USARTinit();
LCDinit();
DDRB |= 0X03;  //PORTB OUT
Delay(4000);
Delay(4000);
//液晶第一行:IP1 IP2 IP3
LCDCOM(0x80); //第一行
while(LCD[str]!='\0') //字符串是否完成
   {
   LCDTATA(LCD[str]);
   str++;//
   }
   str=0;   //跳出来之后清空str=0切记!切记!
//液晶第一行

  while(1)
{
LDelay(2);
//RRRRRRRRRRRRRRRRRRRRRRRR读数据
for(adr=1;adr<4;adr++)
{
  SEND(adr); //发送地址寻找从机,地址ADR从01-03
  LDelay(20); //延时
  }
//RRRRRRRRRRRRRRRRRRRRRRRR读数据
}

}



从机程序:
#include
#include
#pragma interrupt_handler uartrupt:12
unsigned char temp; //接收临时变量
unsigned char sendtata=123;
//QQQQQQQQQQQQQQQQQQQ
//名称:Delay()
//功能:延时程序
//QQQQQQQQQQQQQQQQQQQ
void Delay(int t)
{
while(t--);
}
void LDelay(int t) //延时程序(时间较长)
{
for(;t>0;t--)
{
  Delay(4000);
}
   
}
//AD转换
#define ADC_REF_AVCC 0x40
#define  MUX_ADC0    0x00

unsigned char ADC_Value;
void AD_Init(void)
{
   //CLI();
   ACSR |= (1<    ADCSRA &=~(1<    ADMUX &= 0x20;//清参考电压, ADCn输入端
   ADMUX |=0X40|MUX_ADC0|(1<    ADCSRA |= (1<    ADCSRA |= (1<    ADCSRA |=0x01;//2分频
   SFIOR = 0X00;
   ADCSRA |= (1<    ADCSRA |= (1< }

unsigned char Read_ADC(void)
{
   unsigned char  ADC_dat;
   ADCSRA |= (1<    while(ADCSR&(1<    ADC_dat = ADCH;
   return (ADC_dat);
}

//======================
//名称:USARTinit()
//功能:串行通信初始化,设置引脚功能,波特率,通信方式
//波特率=fosc/16(ubrr+1)
//======================
void USARTinit()
{
UBRRL=25;        //波特率2400
//UBRRH=0x00;
UCSRA=0X0;
UCSRB=0X0;
//UCSRA=RXC|TXC|UDRE|FE|DOR|PE|U2X|MPCM(10100001)
UCSRA|=0X01;     //只接收地址,从机CPCM=1
//UCSRC=URSEL|UMSEL|UPM1|UPM0|USBS|UCSZ1|UCSZ0|UCPOL(10000110)
UCSRC|=0x86;     //设置数据位
//UCSRB=RXCIE|TXCIE\UDRIE|RXEN|TXEN|UCSZ2|RXB8|TXB8(10011000)
UCSRB|=0x9c;     //引脚功能设为TXD与RXD
  
MCUCR|=0x00; //开中断
GICR=0x00;
TIMSK=0x00;
//最后才开总中断
Delay(1000);
SREG=0x80;//开中断
DDRD|=0X08;      //
PORTD&=~0X08;    //未收到主机命令禁止MAX485输出
}
//========================
//名称:发送数据函数
//功能:给主机发数据
//========================
void SEND(unsigned char mydata)
{
DDRD|=0X08; //MAX485允许输出
PORTD|=0X08;
Delay(1000);
  UDR=mydata;
//while(!UDRE);
Delay(1000);   //Delay(100)可发s
  PORTD&=~0X08; //发送后立即转为接收
}


//======================
//名称:接收中断
//功能:接收地址
//======================
void uartrupt()
{  
    temp=UDR; //接收地址
if(temp==0x02)
{
//sendtata=Read_ADC();
  DDRB|=0x01;
  PORTB |= 0X01;//LED
  SEND(sendtata); //发送数据
  }
  
}


//======================
//名称:主函数
//======================
void main()
{
unsigned char adr;
  Delay(4000);
  DDRB |= 0X03;//PORTB OUT
  USARTinit();
   AD_Init();
   
  while(1)
  {
   LDelay(100);   
   PORTB |= 0X01;//LED
   sendtata=Read_ADC();
  }

}


阿莫论坛20周年了!感谢大家的支持与爱护!!

曾经有一段真挚的爱情摆在我的面前,我没有珍惜,现在想起来,还好我没有珍惜……

出0入0汤圆

发表于 2012-3-25 16:06:16 | 显示全部楼层
顶顶 谢谢分享

出0入0汤圆

发表于 2012-3-25 16:08:05 | 显示全部楼层
板凳,谢谢lz分享  

出0入0汤圆

发表于 2012-3-25 20:20:19 来自手机 | 显示全部楼层
马克一下

出0入0汤圆

发表于 2012-3-25 20:20:39 来自手机 | 显示全部楼层
马克一下

出0入0汤圆

发表于 2012-4-10 18:20:16 | 显示全部楼层
来张简要的图就好了。不知道DB8 如何连啊。。

出0入0汤圆

发表于 2012-4-12 17:32:34 | 显示全部楼层
标记中

出0入0汤圆

发表于 2012-5-11 13:18:53 | 显示全部楼层
DING yi ge 顶y一个 最近也在实验下

出0入0汤圆

 楼主| 发表于 2012-5-12 11:25:45 | 显示全部楼层
jacky82512 发表于 2012-5-11 13:18
DING yi ge 顶y一个 最近也在实验下

兄弟,最近你实验的情况怎么样?

出0入0汤圆

发表于 2012-6-15 08:44:23 | 显示全部楼层
下了试试

出0入0汤圆

发表于 2012-6-25 17:06:46 | 显示全部楼层
定顶一下

出0入4汤圆

发表于 2012-6-28 15:01:53 | 显示全部楼层
mark  弱弱的 问一句,485和232程序基本一致,是不是就差在需要判断地址位啊,if(adr==0){}  if(adr==1){}    一直在找程序 但找不到很全的  lz的程序我要好好品味一下

出0入0汤圆

发表于 2012-7-14 09:18:21 | 显示全部楼层
lhuan 发表于 2012-5-12 11:25
兄弟,最近你实验的情况怎么样?

还在实验呢,我开始就做个简单的看看。带协议的还不知道怎么弄。你的呢

出0入0汤圆

发表于 2014-5-22 01:41:46 | 显示全部楼层
顶顶 谢谢分享

出0入0汤圆

发表于 2014-6-5 11:32:44 | 显示全部楼层
好贴。。。。。                           

出0入0汤圆

发表于 2014-6-5 17:04:15 | 显示全部楼层
做过1个485口同时带4块电表的通讯,
效果还不错。

出0入0汤圆

发表于 2014-6-7 10:16:14 | 显示全部楼层
你好,为什么我在做485通信的时候,两块板子单独用调试助手收发没问题,但是直连之后就不行了

出0入0汤圆

发表于 2017-2-9 13:33:08 | 显示全部楼层
请教一个,如果从机上按键。主机如何确定从机是长按按键还是单击按键?

出0入0汤圆

发表于 2017-2-16 13:36:00 | 显示全部楼层
好资料,谢谢。
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-8-26 02:12

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表