公子相 发表于 2024-4-15 14:08:39

UART多机通讯模式

主机MEGA16L,代码如下
#include <iom16v.h> #include <macros.h> #define uchar unsigned char unsigned char data; unsigned char timerl; unsigned char timerh; unsigned char time,rr; unsigned char sendbuf; unsigned char recbuf; uchar   addr,fun,message; uchar   realaddr,realfun,keepaddr,alARM,realalarm;//for²¦Â뿪¹Ø void delay(unsigned char i) {   for(timerl=0;timerl<i;); } void port_init(void) {PORTA = 0x3F;DDRA = 0x00;PORTB |= 0x08;//485DDRB |= 0x08;PORTC = 0x00; //m103 output onlyDDRC= 0xFF;PORTD = 0xC0;DDRD= 0x30; } //TIMER0 initialize - prescale:64 // WGM: Normal // desired value: 1mSec // actual value:1.000mSec (0.0%) void timer0_init(void) {TCCR0 = 0x00; //stopTCNT0 = 0x83; //set count   TCCR0 = 0x03; //start timer } #pragma interrupt_handler timer0_ovf_isr:10 void timer0_ovf_isr(void) {TCNT0 = 0x83; //reload counter valuetimerl++;timerh++; } //TIMER1 initialize - prescale:1024 // WGM: 0) Normal, TOP=0xFFFF // desired value: 1Sec // actual value:1.000Sec (0.0%) void timer1_init(void) {TCCR1B = 0x00; //stopTCNT1H = 0xE1; //setupTCNT1L = 0x7C;TCCR1A = 0x00;TCCR1B = 0x05; //start Timer } #pragma interrupt_handler timer1_ovf_isr:9 void timer1_ovf_isr(void) {//TIMER1 has overflowedTCNT1H = 0xE1; //reload counter high valueTCNT1L = 0x7C; //reload counter low valuetime++; } //UART0 initialize // desired baud rate: 19200 // actual: baud rate:19231 (0.2%) // char size: 9 bit // parity: Disabled void uart0_init(void) {UCSRB = 0x00; //disable while setting baud rateUCSRA = 0x00;UCSRC = BIT(URSEL) | 0x06;UBRRL = 0x19; //set baud rate loUBRRH = 0x00; //set baud rate hiUCSRB = 0xDC; } #pragma interrupt_handler uart0_rx_isr:12 void uart0_rx_isr(void) {//uart has received a character in UDR } #pragma interrupt_handler uart0_tx_isr:14 void uart0_tx_isr(void) {unsigned char i;   rr ++;if(rr < 4){   // for(i=0;i<100;i++);UCSRB &= ~(1<<TXB8);//      UDR = sendbuf;    }   } //call this routine to initialize all peripherals void init_devices(void) {//stop errant interrupts until set upCLI(); //disable all interruptsport_init();timer0_init();timer1_init();uart0_init();MCUCR = 0x00;GICR= 0x00;TIMSK = 0x05; //timer interrupt sourcesSEI(); //re-enable interrupts//all peripherals are now initialized } voidReadSwitch(){   unsigned char    i;   realaddr = 0;   realfun = 0;   PORTB &= 0xF8;   DDRB &= 0xF8;   DDRB |= 0x01;   for(i=0; i<40; i++);   if(!(PINA & 0x20))realaddr |= 0x01;   if(!(PINA & 0x10))realaddr |= 0x02;   if(!(PINA & 0x08))realaddr |= 0x04;   if(!(PINA & 0x04))realaddr |= 0x08;   if(!(PINA & 0x02))realaddr |= 0x10;   if(!(PINA & 0x01))realaddr |= 0x20;   DDRB &= 0xF8;   DDRB |= 0x02;   for(i=0; i<40; i++);   if(!(PINA & 0x01))realaddr |= 0x40;   if(!(PINA & 0x02))realaddr |= 0x80;   if(!(PINA & 0x04))realfun |= 0x01;   if(!(PINA & 0x08))realfun |= 0x02;   if(!(PINA & 0x10))realfun |= 0x04;   if(!(PINA & 0x20))realfun |= 0x08;   DDRB &= 0xF8;   DDRB |= 0x04;   for(i=0; i<40; i++);   if(!(PINA & 0x08))realfun |= 0x40;   if(!(PINA & 0x10))realfun |= 0x20;   if(!(PINA & 0x20))realfun |= 0x10;   PORTB |= 0x01;               DDRB &= 0xF8;   DDRB |= 0x01; } unsigned charchecksum() {    return (sendbuf+sendbuf+sendbuf); } void main(void) { unsigned char i;init_devices();timerl = 0;timerh = 0;time   = 0;   for(;;){      if(timerl > 200){      PORTB ^= 0x01;      timerl = 0;    ReadSwitch();    if(realfun & 0x01){      sendbuf=realaddr;                        sendbuf=0x77;                sendbuf='1';                sendbuf= checksum();      rr = 0;            UCSRB |= (1<<TXB8);               UDR = realaddr;            }    if(realfun & 0x02){      sendbuf=realaddr;      sendbuf=0x77;                sendbuf='2';                sendbuf= checksum();      rr = 0;            UCSRB |= (1<<TXB8);         UDR = realaddr;    }    if(realfun & 0x04){      sendbuf=realaddr;      sendbuf=0x77;                sendbuf='3';                sendbuf= checksum();      rr = 0;            UCSRB |= (1<<TXB8);      UDR = realaddr;    }    if(realfun & 0x08){      sendbuf=realaddr;      sendbuf=0x77;                sendbuf='4';                sendbuf= checksum();      rr = 0;            UCSRB |= (1<<TXB8);      UDR = realaddr;    }    if(realfun & 0x10){      sendbuf= realaddr;      sendbuf= 0x77;                sendbuf= 'F';                sendbuf= checksum();      rr = 0;            UCSRB |= (1<<TXB8);      UDR = realaddr;    }      if(realfun & 0x40){      sendbuf=realaddr;      sendbuf=0x77;                           sendbuf=0x88;                                                                                                                                                                                                          sendbuf= checksum();      rr = 0;            UCSRB |= (1<<TXB8);      UDR = realaddr;    }    if(realfun & 0x20){      sendbuf=realaddr;      sendbuf=0x88;                sendbuf='8';                sendbuf= checksum();      rr = 0;            UCSRB |= (1<<TXB8);      UDR = realaddr;    }       }}}

多机通讯与普通的USART通讯差不多,只不过注意几点:
1,需在复位时将UCSRA寄存器中的MPCM位置1
2,上位机发送地址数据时将第九位置1,这样一来,所有的从机都能通过中断接收到此数据啦各个从机判断接收到的数据是否与自己的地址相符,不符的返回,符合的(只能有1台符合)将MPCM位置0,以便正常的接收发给自己的数据.这些数据的第九位必须为0.其他的从机不会对这些数据产生中断.从而实现多机通讯.
上位机发送 UCSRB |= (1<<TXB8);及第九位数据是1的时候,从机能够能够产生中断,如果第九位0,则从机将数据忽略。如果你发的数据帧:
地址+数据1+数据2+...   
你可以在从机接收到地址数据后,与本机的地址比较,如果相同。说明是发给本机的指令,你可以在中断中将本设置普通的数据模式,用以接收后面的数据。

上面的MEGA16程序是完整的程序,能够在ICCAVR上运行通过的。

下位机是MEGA8
void uart0_init_mulmodel(void) { UCSRB = 0x00; //disable while setting baud rate UCSRA = 0x01; //mul. processor UCSRC = BIT(URSEL) | 0x06; UBRRL = 0x19; //set baud rate lo UBRRH = 0x00; //set baud rate hi UCSRB = 0x94; //9 bit data } void uart0_init_normodel(void) { UCSRB = 0x00; //disable while setting baud rate UCSRA = 0x00; //normal model UCSRC = BIT(URSEL) | 0x06; UBRRL = 0x19; //set baud rate lo UBRRH = 0x00; //set baud rate hi UCSRB = 0x94; //9 bit data } #pragma interrupt_handler uart0_rx_isr:12 void uart0_rx_isr(void) { //uart has received a character in UDR rrr = UDR; rr++; receivetask(); } //数据接收处理函数 void R_KeLi(void) { kelitimer = 0; switch(rr){ case 1: if(rrr == addr){//判断地址是否与本机地址相等 uart0_init_normodel();//如果相等,将本设置位普通模式来接收后面的数据,如果没有这句,后面的数据(第九位为0)将被忽略 } else{ rr = 0; } break; } }
页: [1]
查看完整版本: UART多机通讯模式