|
.
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周年了!感谢大家的支持与爱护!!
曾经有一段真挚的爱情摆在我的面前,我没有珍惜,现在想起来,还好我没有珍惜……
|