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

61 篇文章 6 订阅
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();
  }

}
  • 3
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值