{软件环境:ICC AVR 6.31A硬件平台:atmega128a实现UART0的半双工485通信,中断方式接受,查询方式发送。
485的收发控制引脚为PE2。
供大家学习交流使用}1,以下是delay.h文件#ifndef _delay_h_#define _delay_h_//void delay_nus(unsigned int n);//void delay_nms(unsigned int n);//void delay_1us(void);//void delay_1ms(void);void delay_1us(void) //1us延时函数{NOP();}void delay_nus(unsigned int n) //N us延时函数{unsigned int i=0;for (i=0;i<n;i++) delay_1us();}void delay_1ms(void) //1ms延时函数{unsigned int i;for (i=0;i<1140;i++) ;}void delay_nms(unsigned int n) //N ms延时函数{unsigned int i=0;for (i=0;i<n;i++) delay_1ms();}#endif/***********2,以下是uart.h头文件/***********uart.h使用端口:uart0及控制端口PE2; uart1及控制端口PD4晶振:11.0592M查询方式发送,中断接收。
*************************************************/#ifndef _uart_h#define _uart_h#include <iom128v.h>#include <macros.h>#include "delay.h"#define fosc 11059200#define baud 9600#define uchar unsigned char//#define amount 8 //data amount//uchar inbox[amount]; //transmited and received data buff.//uchar buff = 0;//unsigned char inbox[10];/****uart0 initialize************/void Uart0_initial(void){UCSR0B = 0x00;// disable while setting uartUCSR0A = 0x00;UCSR0C = (1<<UCSZ01) | (1<<UCSZ00);// 8bit +1bit stopUBRR0L = (fosc/16/(baud+1))%256;//此公式为datasheet上,是正确的// UBRR0H = (fosc/16/(baud+1))/256;//网上例程很多用baud+1,经试验不行// UCSR0B = (1<<RXCIE0)|(1<<RXEN0) | (1<<TXEN0); //RXCIE0 RXEN TXEN PORTE |=BIT(PE2);// Set PE2,DDRE |= BIT(PE2); // RXD0 enable.}/**uart1 initialize**************/void Uart1_initial(void){UCSR1B = 0x00;//disable while setting uartUCSR1A = 0x00;UCSR1C = (1<<UCSZ11) | (1<<UCSZ10);//8bit + 1 stopUBRR1L = (fosc/16/baud-1)%256;UBRR1H = (fosc/16/baud-1)/256;UCSR1B = (1<<RXCIE1) | (1<<RXEN1) | (1<<TXEN1);// RXCIE RXEN TXEN PORTD |= BIT(PD4); //Set PD4DDRD |= BIT(PD4); //RXD1 enable.}/***uart0 transfer one char****/void putchar0(uchar c){PORTE &=~ BIT(PE2);delay_nms(5);while (!(UCSR0A&(1<<UDRE0)));UDR0 = c;delay_nms(5);//PORTE |= BIT(PE2);}/***uart0 transfer char strings***/void puts0(uchar *s){uchar k=0;CLI();//PORTE &=~ BIT(PE2);delay_nms(5);while (k<8){putchar0(*s);s++;k++;}PORTE |= BIT(PE2);delay_nms(3);SEI();}/****uart1 transfer one char **/void putchar1(unsigned char c){CLI();PORTD &=~ BIT(PD4);while (!(UCSR1A&(1<<UDRE1)));UDR1 = c;SEI();//PORTD |= BIT(PD4); //set as RX after TX. }/***uart1 transfer char strings**/void puts1(uchar *s){while (*s){putchar1(*s);}}/***uart0 RXD interrupt processing****//**************************************#pragma interrupt_handler uart0_RX_interrupt:19void uart0_RX_interrupt(void){//UCSR0B = 0x00; //disable uart0 while handling interrupt.buff = UDR0;PORTE &=~ BIT(PE2);delay_nms(3); //收转发设置控制引脚后,要延时,换高频晶振需加大此延时。
putchar0(buff);puts0("Test OK!");delay_nms(3);PORTE |= BIT(PE2);//UCSR0B = (1<<RXCIE0)|(1<<RXEN0) | (1<<TXEN0); //RXCIE0 RXEN TXEN }**************************************/#endif/********3,以下是CRC8校验头文件******************//*crc8校验程序*/#ifndef _CRC8_H_#define _CRC8_H_/*******************************************************unsigned char CRC8(unsigned char *ptr, unsigned char len){unsigned char i;unsigned char crc = 0;while(len--!=0){for(i=1; i!=0; i*=2){if((crc&1)!=0) {crc/=2; crc^=0x8C;}else crc/=2;if((*ptr&i)!=0) crc^=0x8C;}ptr++;WDR();}return(crc);}*******************************************************/ unsigned char CRC8(unsigned char *ptr, unsigned char len){if(len == 7)return (0xAA);}#endif/*********4,以下是主程序**************/#include <iom128v.h>#include <macros.h>#include "delay.h"#include "CRC8.h"#include "uart.h"#define uchar unsigned char#define amount 8uchar inbox[amount]; //收件箱uchar sendbox[amount]; //发件箱uchar buf_used = 0; //接收的数据个数uchar buf_flag = 0; //接收缓冲区满标志位uchar buf_saved = 0; //记忆收发缓存中未使用的个数uchar fun_code = 0; //存放功能代码uchar action_code = 0; //存放功能数据uchar key = 0;uchar key_code = 0;uchar relay_status = 0; //继电器状态uchar key_buf = 0x1F; //存储开关量的值uchar used_times = 0; //记录使用状况void Device_initial(void){//初始化各IO端口和设备PORTC |= 0x3F;DDRA |= 0xFF; //PORTA全部用于1602DDRB |= 0xF6; //PORTB比较混乱,具体参考电路图DDRC |= 0x3F; //PORTC.0 - PORTC.5为电源组件反馈端信号输入端DDRD |= 0x00;//PORTE |= 0xFC; //PE = 1111 1100 =0xFC PORTD待定DDRE |= 0x06; //DDRE = 0000 0110=0x06SEI(); //PORTE.0为RXD0,PORTE.1为TXD0,PORTE.2为485(0号)控制端;PORTE3~7为继电器控制端口// watchdog_INI();}#pragma interrupt_handler uart0_RX_interrupt:19void uart0_RX_interrupt(void) //中断方式接受函数{inbox[buf_used] = UDR0;if(inbox[0] == 0x0A)buf_used+=1;if(buf_used == 8){buf_flag = 1;buf_used = 0;}}void TX(uchar a,uchar b) //查询方式发送函数{sendbox[0] = 0x0A;sendbox[1] = 0xFF;sendbox[2] = 0x0A;sendbox[3] = 0x07;sendbox[4] = a;sendbox[5] = b;sendbox[6] = 0x0D;sendbox[7] = CRC8(sendbox,amount-1);puts0(sendbox);//WDR();}void Key_scan(void){key_code = PINE;key = key_code>>3;if(key!= key_buf){delay_nms(15); //消抖if(key != key_buf)//开关量与上次不同,则上发开关量状态到ARM {key_buf = key;while(1){while(buf_flag == 0){TX('N',key);delay_nms(300);}CLI(); //禁止接收//buf_used = 0;buf_flag =0;inbox[0] = 0;if(inbox[7] == CRC8(inbox,amount-1)){if(inbox[4] == 'A'&&inbox[5] == 'R') //应答正确。