AVR单片机串口多机通讯程序
单片机多机通信实现
单片机多机通信实现随着科技的进步和应用的需求,单片机成为了嵌入式系统中不可或缺的一部分。
在很多应用场景中,我们需要将多个单片机之间进行通信,以实现数据的传输和协同工作。
本文将介绍单片机多机通信的实现方法。
一、串口通信串口通信是最常见和简单的单片机通信方式之一。
单片机通过串口将数据以字节的形式传输给另一个单片机。
常见的串口通信协议有RS232、RS485和UART等。
其中,RS232是单片机与计算机之间的标准通信协议,而RS485适用于单片机与多个设备之间的通信。
串口通信需要注意以下几个方面:1. 波特率的设置:通信双方需要设定相同的波特率,以确保数据的准确传输。
2. 数据格式的规定:包括数据位、校验位和停止位等,通讯双方需要设置相同的数据格式。
3. 通信控制的实现:通过编程控制单片机的串口发送和接收功能,实现数据的传输。
二、I2C通信I2C(Inter-Integrated Circuit)是一种串行总线协议,它可实现多个单片机的通信和协同工作。
I2C通信需要引入一个主设备和多个从设备的概念,主设备控制通信的起止和数据的传输,从设备用于接收和发送数据。
I2C通信需要注意以下几个方面:1. I2C地址的分配:每个从设备通过唯一的地址与主设备进行通信,地址的分配需要事先规划好。
2. 数据的读写操作:通过发送特定的控制信号,主设备可以向从设备发送读或写的命令,并接收从设备返回的数据。
3. 时序的控制:I2C通信依赖于时钟信号和数据信号的同步,通信双方需要根据协议规定好时序的控制。
三、SPI通信SPI(Serial Peripheral Interface)通信是一种全双工、同步的通信协议。
它通过4根线进行通信,包括时钟、数据输入、数据输出和片选信号。
SPI通信适用于多个主设备与多个从设备之间的通信,可以实现数据的传输和设备的控制。
SPI通信需要注意以下几个方面:1. 主从设备的选定:SPI通信中,每次只有一个主设备能够与从设备进行通信,其他设备通过片选信号进行选择。
avr单片机SPI双机通信
MCUCSR = 0x80;//禁止JTAG
GICR = 0x00;
port_init();
spi_init();
sei();//开全局中断
}
//主函数
int main(void)
{
init_devices();
SPCR = 0xF1;
SPSR = 0x01;
}
SIGNAL(SIG_SPI) //一个字节发送或接收完成中断
{
PORTD=SPDR;
}
void spi_write(uchar sData)//功能:使用SPI发送一个字节
{
SPDR = sData;
{
DDRA=0XFF;
PORTA=spi_read();
}
//功能:使用SPI发送一个字节
void spi_write(uchar sData)
{
SPDR = sData;
while(!(SPSR & BIT(SPIF)));
//sData=SPDR;//读从机发回来的数据
}
//主函数
int main(void)
{
init_devices();
spi_write(0X09);
while(1)
{
NOP();
}
return 0;
}
从机:
//SPI双机通信 从机
//发送0x06,PA0~3接收
//SPI双机通信 主机
//发送0x09,接收方PD0~3,对应点小灯
//包含所需头文件
AVR复习笔记--AVR单片机SPI多机通讯
AVR复习笔记--AVR单片机SPI多机通讯
最近决定复习下AVR 单片机,其实也是为了借此复习下几种简单的通
信协议,包括串口,SPI,I2­C 等。
本来以为一两个晚上就能搞定的事儿,
没想到竟耗费了一周晚上空余的时间。
当然主要是这次的要求要提高点,实现SPI 的多机通信,
不但要发数据还要回传数据。
实际中还是遇到了比我想象中要大的多的困难。
即使是现在的实现方式也不是很理想。
下面是spi 部分的代码,由于spi 接收发送用的同一终端,感觉使用起来形式
不怎么样,还是采用了轮询标志位的方式
Code#include”spi.h”staticcharmode=1;voidspi_init(charflag){chartmp=0;mode=flag; if(mode==1){DDR_SPI=(1 在我的例子中有一个主机,两个从机
进行如下通信
发送至1 号从机1 ,2
发送至2 号从机3 ,4
发送至1 号从机5 ,6
发送至2 号从机7 ,8
从机1 收到数据后回传1
从机2 收到数据后回传2
下面还是看代码
Code#include”basic.h”//自己写的常用函式#include”usart.h”//usart初始化函式
#include”spi.h”intmain(void){chartmp;usart_init(9600);spi_init(1);PORTB|=(1。
AVR单片机USART双机通讯
第 13 卷
本文所给出的主机的示例程序和从机的示例程序 , 已在 AVR 系列的 ATMEGA16 单片机上进行实 验并通过. 参考文献:
1] 沈文. AVR 单片机 C 语言开发入门指导[ M] . 北京: 清华大学出版社, 2003. [ [ 2] 金春林. AVR 系列单片机 C 语言编程与应用实例[ M] . 北京: 清华大学出版社, 2003. [ 3] 张军. AVR 单片机应用系统开发典型实例[ M] . 北京: 中国电力出版社, 2005. [ 4] 郝云鹏. AVR 单片机 SPI 双机通讯[ J] . 鞍山师范学院学报, 2010 , ( 4 ) : 52-53. [ 5] 郝云鹏. AVR 单片机 C 语言总纲[ J] . 鞍山师范学院学报, 2008 , ( 4 ) : 59-62. [ 6] ATMEL Corporation. AVR 单片机 ATmega16 中文说明书[ M] . 美国: ATMEL Corporation, 2001.
Abstract: This paper introduces the port connection by AVR Microcontroller USART Communication between two AVR Microcontroller, installation of UCSRB of control Register, and provides practical two programs. Key words: AVR Microcontroller; USART Communication; ATMEGA16 ( 责任编辑: 张冬冬)
AVR Microcontroller USART Communication between Two AVR Microcontroller
基于AVR单片机的串口通信
囝2
主从机软件部分如下: 下面为主机的初始化和中断服务程序
.include“8535def.inc”
Ij。砷reset
.clef SPldrd=r2
.clef .def .clef
tempi=r16 temp2=r17 ent=r18
.equ block0=¥0060
.dqu k啦;dI=50
·eseg
参考文献 1李勋,耿德根.AVR单片机应用技术.北京:北京航空航天
大学出版社,2000 2丁化成,耿德根,李君凯.A'VR单片机应用设计.北京:北京
航空航天大学出敝社,2002 3宋建国AVR单片机原理及应用.北京:北京航空航天大学
出舨社,2000 4耿德根,宋建国,马潮,叶勇建.AVR高速嵌人式单片机原理
本文研究的血红细胞沉降率测量仪与传统血红细胞沉降率测量仪相比较,具有以下创新点: 1)提出新的快速血红细胞沉降率测量方法,提高了血红细胞沉降率的测量速度; 2)采用CPLD和AVR单片机相结合,实现电动机的高精度、高稳定性控制,从而提高了血红细胞沉降率的测量精度; 3)在医疗设备中应用红外测量技术。 最后对设计制作的血红细胞沉降率测量仪进行了实验验证,分析了误差来源以及改进方法。实验结果表明,本文设计的ESR测量仪的测量精度高,稳 定性好,达到了设计要求。
ATMEL公司研发的AVR单片机提供一个同步串行通信接口SPI(Serial Peripheral Interface),用户能够通过计算机的并行接口或串行接口对其内部程 序存储器编程.实际上,利用串口实现AVR单片机ISP(In Sys-tern Programmable)功能就是使用计算机的串口来驱动AVR单片机ISP串行编程所需的信号波 形,从而实现计算机对AVR单片机的编程.首先介绍AVR单片机ISP功能的原理,然后讨论利用串口实现AVR单片机ISP功能的一种方法,给出编程电缆原理图、 编程电缆监控程序通信协议和编程工具软件.
基于AVR单片机的双机通信三种实现方式
基于A VR单片机的双机通信三种实现方式原理分析及应用比较施柏鑫北京邮电大学信息工程学院(100876)E-mail:boxin.shi@摘要:本文基于AVR单片机ATmega16的三种硬件通信方式——SPI、USART、TWI,实现两片单片机的通信。
通过分析这三种方式的硬件内部结构、寄存器的使用方法、数据传输过程及其各自的特点和扩展应用,比较他们的异同,为合理选择适当的通信方式提供了理论依据。
关键词:AVR单片机、通信、SPI、USART、TWI0.引言在很多工程应用中,一片单片机往往不能达到预期的要求。
这就需要两片或者两片以上的单片机协同工作。
实现这一问题的核心技术是单片机之间的相互通信。
Atmel公司的A VR 系列单片机支持多种硬件通信方式,根据相应的通信协议,我们可以实现单片机之间高速、可靠的数据传输。
本文以A VR单片机ATmega16为例,充分利用该芯片的硬件资源,不外接任何芯片,用三种方式——SPI、USART、TWI实现双机通信,并对三种通信方式的原理和应用进行分析和比较。
1.串行外设接口SPI串行外设接口SPI(Serial Peripheral Interface)是由Motorola公司推出的工业标准的同步串行接口,是一种全双工、四线通信的系统。
它可以用于单片机之间的互联,也可以外接支持该通信方式的外设。
ATmega16 的SPI接口支持7种可编程的比特率,可以设置传输结束中断标志、写碰撞标志检测,支持主机倍速模式和闲置模式唤醒[1]。
两片用SPI互连的单片机有主从之分,为串行传输提供时钟信号SCK的一方是主机,接受时钟的另一方为从机。
双机通信的方法是将主机和从机的四根信号线SS、SCK、MOSI、MISO直接对应相连。
ATmega16的SPI内部结构框图如图1.1所示[3]。
- 1 -图1.1 SPI内部结构框图从图中我们可以看出,ATmega16的SPI寄存器有三个:SPDR(数据寄存器),SPCR (控制寄存器)和SPSR(状态寄存器)。
单片机多机通信程序
单片机多机通信主机程序:#include <reg52.h> /*52系列单片机头文件*/#define uchar unsigned char /*宏定义*/#define uint unsigned int#define BN 6uchar rbuf[6]; /*接收数据存储数组*/uchar SLA VE; /*从机地址*/uchar code tbuf[6]={0x12,0x23,0x34,0x45,0x46,0x47}; /*待发送的数据*/ void err(void) /*地址错,发复位信号*/{SBUF=0xff;while(TI!=1);TI=0;}uchar master(uchar addr,uchar command) /*发送与接收功能函数*/{uchar aa,i,p;while(1){SBUF=SLA VE; /* 发呼叫地址*/while(TI!=1);TI=0;while(RI!=1);RI=0; /* 等待从机回答*/if(SBUF!=addr)err(); /* 若地址错,发复位信号*/else{ /* 地址相符*/TB8=0; /* 清地址标志*/SBUF=command; /* 发命令*/while(TI!=1);TI=0;while(RI!=1);RI=0;aa=SBUF; /* 接收状态*/if((aa&0x08)==0x08) /* 若命令未被接收,发复位信号*/{TB8=1;err();}else{if(command==0x01) /* 是发送命令*/{if((aa&0x01)==0x01) /* 从机准备好接收*/{do{p=0; /* 清校验和*/for(i=0;i<BN;i++){SBUF=tbuf[i]; /* 发送一数据*/p+=tbuf[i];while(TI!=1);TI=0;}SBUF=p; /* 发送校验和*/while(TI!=1);TI=0;while(RI!=1);RI=0;}while(SBUF!=0); /* 接收不正确,重新发送*/TB8=1; /* 置地址标志*/return(0);}else{if((aa&0x02)==0x02) /* 是接收命令,从机准备好发送*/{while(1){p=0; /* 清校验和*/for(i=0;i<BN;i++){while(RI!=1);RI=0;rbuf[i]=SBUF; /* 接收一数据*/p+=rbuf[i];}while(RI!=1);RI=0;if(SBUF==p){SBUF=0X00; /* 校验和相同发"00" */while(TI!=1);TI=0;break;}else{SBUF=0xff; /* 校验和不同发"0FF",重新接收*/while(TI!=1);TI=0;}}TB8=1; /* 置地址标志*/P2=rbuf[1];return(0);}}}}}}}void main(){TMOD=0x20; /* T/C1定义为方式2 */TL1=0xfd;TH1=0xfd; /* 置初值,波特率9600,晶振11.0592MHz */PCON=0x00; /*不倍频*/TR1=1; /*启动定时器*/SCON=0xf8; /* 串行口为方式3 */SLAVE=0x01; /*1号从机地址*/master(SLAVE,0x01);master(SLAVE,0x02);SLAVE=0x02; /*2号从机地址*/master(SLAVE,0x01);master(SLAVE,0x02);SLAVE=0x03; /*3号从机地址*/master(SLAVE,0x01);master(SLAVE,0x02);while(1);}单片机多机通信从机程序(以01H从机为例):#include <reg52.h> /*52系列单片机头文件*/#define uchar unsigned char /*宏定义*/#define SLA VE 0x01 /*1号从机地址*/#define BN 6uchar trbuf[6]={0x12,0x13,0x14,0x15,0x16,0x17}; /*发送数据存储数组*/ uchar rebuf[6]; /*接收数据存储数组*/bit tready;bit rready;void str(void); /* 发数据块函数声明*/void sre(void); /* 收数据块函数声明*/void main(void){TMOD=0x20; /*T/C1定义为方式2*/TL1=0xfd;TH1=0xfd; /* 置初值,波特率9600,晶振11.0592MHz */PCON=0x00; /*不倍频*/TR1=1; /*启动定时器*/SCON=0xf0; /*串行口为方式3*/ES=1; /*开串口中断*/EA=1; /*开串行口中断*/while(1){tready=1;rready=1;} /*假定准备好发送和接收*/}void ssio(void) interrupt 4 /*串行口中断*/{uchar a;RI=0;ES=0; /*关串行口中断*/if(SBUF!=SLAVE){ES=1;goto reti;} /*非本机地址,继续监听*/SM2=0; /* 取消监听状态*/SBUF=SLAVE; /* 从本地址发回*/while(TI!=1);TI=0;while(RI!=1);RI =0;if(RB8==1){SM2=1;ES=1;goto reti;}/* 是复位信号,恢复监听*/a=SBUF; /* 接收命令*/if(a==0x01)/* 从主机接收的数据*/{if(rready==1)SBUF=0x01;/* 接收准备好发状态*/ elseSBUF=0x00;while(TI!=1);TI=0;while(RI!=1);RI=0;if(RB8==1){SM2=1;ES=1;goto reti;}sre(); /* 接收数据*/}else{if(a==0x02) /* 从机向主机发送数据*/{if(tready==1)SBUF=0x02; /* 发送准备好发状态*/ elseSBUF=0x00;while(TI!=1);TI=0;while(RI!=1);RI=0;if(RB8==1){SM2=1;ES=1;goto reti;}str();/* 发送数据*/}else{SBUF=0x80; /* 命令非法,发状态*/while(TI!=1);TI=0;SM2=1;ES=1; /* 恢复监听*/}}reti:;}void str(void) /* 发数据块*/{uchar p,i;tready=0 ;do{p=0;/* 清校验和*/for(i=0;i<BN;i++){SBUF=trbuf[i]; /* 发送一数据*/p+=trbuf[i];while(TI!=1);TI=0;}SBUF=p; /* 发送校验和*/while(TI!=1);TI=0;while(RI!=1);RI=0;}while(SBUF!=0);/* 主机接收不正确,重新发送*/SM2=1;ES=1;}void sre(void) /* 接收数据块*/{uchar p,i;rready=0 ;while(1){p=0; /* 清校验和*/for(i=0;i<BN;i++){while(RI!=1);RI=0;rebuf[i]=SBUF; /* 接收数据*/p+=rebuf[i];}while(RI!=1);RI=0;if(SBUF==p){SBUF=0x00;break;} /* 校验和相同发"00"*/else{SBUF=0xff; /* 校验和不同发"0FF",重新接收*/while(TI==0);TI=0;}}P1=rebuf[1];SM2=1;ES=1;}。
AVR程序范例(USART串口通讯)
}
}
interrupt[USART0_RXC] void usart0_rx(void)//USART接收中断处理程序
{
temp=UDR0;
usart_char_send(temp);
//-------------------------------//利用数组RsBuf来装接收到的字符串
UBRR0H = 0x00; //波特率寄存器H:
SREG = 0x80; //开总中断
}
//*********************************// ADC模块
void adc_init(void) //ADC初始化
{
ADCSRA=0xe3;//自动转换方式:ADC使能,ADC开始转换,自动触发使能,ADC预频:8分频
RsBuf[RsBytes]=temp;
RsBytes++;
if(RsBytes>10)//如果超过10个,则清零
{
for(clear=0;clear<=10;clear++)
{
RsBuf[clear]=0;
}
//flag=0;
RsBytes=0;
}
//------------------------------//
欢迎一起交流单片机,QQ:669892537
#include "mega64.h"
#include "string.h"
#define uint unsigned int
#define uchar unsigned char
AVR单片机与PC机串口通讯程序
A V R单片机与P C机串口通讯程序(总3页)本页仅作为文档封面,使用时可以删除This document is for reference only-rar21year.MarchProteus环境下完成本实验时,需要roteus中设COMPIM////-----------------------------------------------------------------#define F_CPU 4000000UL //4M晶振#include <avr/>#include <avr/>#include <util/>#define INT8U unsigned char#define INT16U unsigned int//数字串接收缓冲struct{INT8U Buf_Array[100]; //缓冲空间INT8U Buf_Len; //当前缓冲长度} Receive_Buffer ;//清空缓冲标志INT8U Clear_Buffer_Flag = 0;//0-9的数字编码,最后一位为黑屏const INT8U SEG_CODE[] ={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x00}; char *s = "\n", *p;//------------------------------------------------------------------// USART初始化//------------------------------------------------------------------void Init_USART(){UCSRB = _BV(RXEN)|_BV(TXEN)|_BV(RXCIE);UCSRC = _BV(URSEL)|_BV(UCSZ1)|_BV(UCSZ0);UBRRL = (F_CPU/9600/16-1)%256;UBRRH = (F_CPU/9600/16-1)/256;}//------------------------------------------------------------------// 发送一个字符//------------------------------------------------------------------void PutChar(char c){if(c=='\n') PutChar('\r');UDR = c;while(!(UCSRA&_BV(UDRE)));}//------------------------------------------------------------------// 显示所接收的数字字符(数字字符由PC串口发送,AVR串口接收) //------------------------------------------------------------------void Show_Received_Digits(){INT8U i;for(i=0;i<;i++){PORTC= SEG_CODE[[i]];_delay_ms(400);}}//------------------------------------------------------------------// 主程序//------------------------------------------------------------------int main(){= 0;DDRB = 0x00; PORTB = 0xFF;DDRC = 0xFF; PORTC = 0x00;DDRD = 0x02; PORTD = 0xFF;MCUCR = 0x08;GICR =_BV(INT1);Init_USART();sei();while(1)Show_Received_Digits();}//-----------------------------------------------------------------// 串口接收中断函数//-----------------------------------------------------------------ISR (USART_RXC_vect){INT8U c= UDR;//如果接收到回车换行符则设置清空缓冲标志if(c=='\r'||c=='\n') Clear_Buffer_Flag=1;if(c>='0'&&c<='9'){//如果上次曾收到清空缓冲标志,则本次从缓冲开始位置存放 if(Clear_Buffer_Flag==1){= 0;Clear_Buffer_Flag = 0;}//缓存新接收的数字[]= c-'0';//刷新缓冲长度(不超过最大长度)if<100) ++;}}//-----------------------------------------------------------------// INT1中断函数(向PC发送字符串)//-----------------------------------------------------------------ISR (INT1_vect){INT8U i = 0;while(s[i]!='\0')PutChar(s[i++]);// 向PC发送字符串}。
AVR 单片机 串口通信 串行通讯 详细例程介绍
Atmega128 有两个串口:USART0 与 USART1 以 USART0 为例
串口的初始化包括:
传输模式的选择:同步还是异步,默认为异步模式,可通过选择 USART 控制和状态 寄存器 UCSR0C 中的 UMSEL 位来选择,UMSEL 为 0,是异步模式. 波特率的设置:通信的双方都必须有相同的波特率,波特率可以通过设置波特率 发生寄存器 UBRR0 来确定,UBRR0 为两字节 16 位的寄存器,可分为 UBRR0H 和 UBRR0L.同时起作用的还有 UCSR0A 中的波特率加倍位 UX2,当 UX2 为 1 时设置的 波特率加倍.
3、设置 UCSR0C:
Bit6-UMSEL0:USART0 的模式选择,0 为异步模式,1 为同步模式 Bit5:4-UPM01:0:奇偶校验模式,00 禁止,01,保留,10 偶校验,11,奇校验 Bit3-USBS0:停止位的选择,0 停止位为 1bit,1 停止位为 2-bits Bit2:1-UCSZ01:0:字符长度,当 UCSZ02 为 0 时,00 表示 5 位,01 表示 6 位,10 表示 7 位,11 表示 8 位.当 UCSZ02 为 1 时,11 表示 9 位.(UCSZ02 为 UCSR0B 里的一位寄存器)
{ putchar0(*s); s++; }
putchar0(0x0a);//回车换行 putchar0(0x0d); }
/******************************************************************* ********* 函数功能:主程序 入口参数: 出口参数: ******************************************************************** ********/ void main(void) { unsigned char i;
AVR简单的串口通信程序
AVR简单的串口通信程序
本例子是学习AVR 的串口通信时候编写的一个简单的串口通信的程序,运行的时候先向串口发送一个数据0x12,然后等待接收,当PC 机发送一个数据到单片机,单片机就对这个数据进行加1 处理,然后发回到PC 机显示。
以下是串口通信时候的界面和串口通信的源程序。
/***********************************************/
/************AVR USART 串口调试****************/
/************ClimberWin 2008.6.29**************/
/*CPU:ATMEGA32L 4MHZ 外部晶振(熔断位需要先配置好外部晶振)*/ /*说明:AVR 串口是通过UDR 发送出去的,类似于51 单片机的SBUF*/
/*程序功能:能够通过串行数据发送给PC 机0x12 数据,接收上位机数据并且+1 后发送回上位机*/
#include //AVR I/O 口定义头文件
#include // 延时头文件调用
#include interrupt.h> // 中断头文件调用
#define uchar unsigned char
//引脚定义
#define AVR_RXD 0 //PD0 RXD
#define AVR_TXD 1 //PD1 TXD
//常量定义
#define BAUDRATE 9600 //波特率定义
uchar UART_MID; //定义一个缓存区数据临时存储地址
/*******************串口接收中断服务程序*************************/。
一个不错的AVR的串口程序
一个不错的A VR的串口程序一个不错的avr的串口通讯代码,收藏于此,以备后用。
在此谢谢原创者。
[code]/******************************************************************************************* ******** 文件名: Comm.H* 说明:* 1> 这一版本中最大的接收和发送缓存为255为INT8U类型的最大值******************************************************************************************** ******/#ifdef COMM_GLOBALS#define COMM_EXT#else#define COMM_EXT extern#endif/******************************************************************************************* ******** 全局常量******************************************************************************************** ******/#define COMM_MODULE_EN 1 // 串口模块总使能0禁止// 当串口的接收需要任务协助处理时下面两个定义有效//#define TaskComm1Prio 1 // 定义串口0接收任务ID 注意: 在CONFIG.H中统一定义//#define TaskComm2Prio 2 // 定义串口1接收任务ID#define COMM1_MEM_SEL // 串口0各种控制变量存储区选择非C51一般为空#define COMM2_MEM_SEL // 串口1各种控制变量存储区选择非C51一般为空#define COMM_CONST_SEL // 串口数据常量存储区选择非C51一般为const或static #define COMM0_VECTOR // 串口0中断函数入口编号#define COMM1_VECTOR // 串口1中断函数入口编号#define X0N 17 // 流控制字符继续发送20%#define XOFF 19 // 流控制字符停止发送70%////////////////////////////////////////////////------------串口配置----------#define COMM_MODE 1 // 通信模式0异步正常模式1异步倍速模式2同步主机模式#define COMM_MORE_CPU_MODE 0 // 多处理器模式1为多处理器模式有效0为无效#define COMM_ACCEPT_ISR_EN 1 // 接收结束中断(1)使能(0)禁止#define COMM_SEND_ISR_EN 1 // 发送结束中断(1)使能(0)禁止#define COMM_DA TAFREE_ISR_EN 1 // 数据寄存器空中断(1)使能(0)禁止#define COMM_SYN_CLOCK 1 // 同步工作模式时钟极性(1)下降沿(0)上升沿// 两个处理CLK模块临界数据的两个宏这里使用OS的临界宏#define COMM_ENTER_CRITICAL() OS_ENTER_CRITICAL() // 进入临界宏默认COMM_ENTER_CRITICAL() EA=0#define COMM_EXIT_CRITICAL() OS_EXIT_CRITICAL() //退出临界宏默认COMM_ENTER_CRITICAL() EA=1// 串口0的常量定义#define COMM1_UNIT_EN 1 // 串口0模块使能0禁止#define COMM1_DA TA_STREAM_EN 0 // ASCII方式通讯时可采样XON/XOFF数据流模式来保证数据传输#define COMM1_OS_SEL 1 // 选择在RTOS中使用则调用OSIntSendSignal 通知接收任务处理// 串口数据则启用定义TaskComm1Prio即接收任务ID 0=禁止#define COMM1_OS_SIGNAL_SEL 1 // 0选择发送信号1选择释放信号量同时COMM1_OS_SEL要使能// 来通知接收任务处理数据#define COMM1_RXD_EN 1 // 串口0接收部分使能0禁止#define COMM1_GETNMSGS_EN 0 // 串口0的数据计数检测函数使能0禁止#define COMM1_GETS_EN 0 // 串口0接收多数据0禁止#define COMM1_RXD_SIZE 255 // 串口0的接收缓存配置需要立即读数据否则弃数据必须>=1 #define COMM1_TXD_EN 1 // 串口0发送部分使能0禁止#define COMM1_PUTS_EN 0 // 串口0发送多数据0禁止#define COMM1_TXD_SIZE 128 // 串口0的发送缓存配置必须>=1//////////////////////////////////////////////// --------------串口的各种返回信息不能更改------------#define COMM_ERR 0 // 串口配置有错误#define COMM_NO_ERR 1 // 串口配置没有错误#define COMM_BAD_BAUD 2 // 波特率错误#define COMM_BAD_MODE 3 // 串口工作为错误的工作方式#define COMM_RXD_EMPTY 4 // 接收缓存没有数据为空#define COMM_RXD_FALSE 5 // 接收数据失败只多字节接收时返回此信息#define COMM_RXD_OK 6 // 接收数据正确#define COMM_TXD_FALSE 7 // 发送失败#define COMM_TXD_OK 8 // 发送正确#define COMM_TXD_FLOOD 9 // 发送数据溢出快速或多字节数据发送时缓存溢出////////////////////////////////////////////#if (COMM_MODE == 0)||(COMM_MODE == 1) // 异步正常模式串,异步倍速模式串#define UMSEL_MODE 0#define UCPOL_MODE 0#elif COMM_MODE == 2 // 同步模式串#define UMSEL_MODE BIT(UMSEL)#if COMM_SYN_CLOCK == 0 // 同步工作模式时钟极性#define UCPOL_MODE 0#else#define UCPOL_MODE BIT(UCPOL)#endif#else // 选择其他模式则停止编译#error "(COMM_MODE)通信模式设置错误! "#endif#if COMM_MORE_CPU_MODE == 0 // 处理器模式1为多处理器模式有效0为无效#define MPCM_MODE 0 //#elif COMM_MORE_CPU_MODE == 1#define MPCM_MODE BIT(MPCM)#else#error "请正确配置多处理器模式中断使能信号(COMM_MORE_CPU_MODE)!"#endif#if COMM_ACCEPT_ISR_EN == 0 // 接收结束中断(1)使能(0)禁止#define RXCIE_MODE 0 //#elif COMM_ACCEPT_ISR_EN == 1#define RXCIE_MODE BIT(RXCIE)#else#error "请正确配置接收结束中断中断使能信号(COMM_ACCEPT_ISR_EN)!"#endif#if COMM_SEND_ISR_EN == 0 // 发送结束中断(1)使能(0)禁止#define TXCIE_MODE 0 //#elif COMM_SEND_ISR_EN == 1#define TXCIE_MODE BIT(TXCIE)#else#error "请正确配置发送结束中断中断使能信号(COMM_SEND_ISR_EN)!"#endif#if COMM_DA TAFREE_ISR_EN == 0 // 数据寄存器空中断(1)使能(0)禁止#define UDRIE_MODE 0 //#elif COMM_DA TAFREE_ISR_EN == 1#define UDRIE_MODE BIT(UDRIE)#else#error "请正确配置数据寄存器空中断使能信号(COMM_DATAFREE_ISR_EN)!"#endif////////////////////////////////////////////////#define none 0#define even 2#define odd 3/******************************************************************************************* ************** 全局变量和数据类型******************************************************************************************** ************/#if COMM_MODULE_EN > 0#endif/******************************************************************************************* ************** 函数******************************************************************************************** ************//* COMM1有关接口函数集*/INT8U Comm1CfgPort (INT32U baud, INT8U parity, INT8U bits, INT8U stops);void Comm1VarInit (void);/* COMM1接收有关函数*/INT8U Comm1RxGetChar (INT8U *Data);INT8U Comm1RxGetNMsgs (void);INT8U Comm1RxGetsChar (INT8U *s, INT8U len);/* COMM1发送有关函数*/INT8U Comm1TxInBuf (INT8U Data); // 数据进入发送缓存#define Comm1TxPutChar Comm1TxInBuf//INT8U Comm1TxPutChar (INT8U Data);INT8U Comm1TxPutsChar (INT8U *s, INT8U len);/******************************************************************************************* ************** End Of File******************************************************************************************** ************/[/code][code]/******************************************************************************************* ******** 文件名: Comm.C* 说明: 暂不支持9位数据流* 1> 这一版本中最大的接收和发送缓存为255为INT8U类型的最大值******************************************************************************************** ********/#define COMM_GLOBALS#include "includes.h"#if COMM_MODULE_EN > 0/******************************************************************************************* ******** 局部常数******************************************************************************************** ******/#ifndef MCU_Fosc // MCU的晶振频率设置这是计算波特率必须的参数#error "no defien MCU_Fosc e.g. #define MCU_Fosc 11059200L"#endif/******************************************************************************************* ************** 局部变量******************************************************************************************** ************/static INT8U COMM1_MEM_SEL Comm1RxBuf[COMM1_RXD_SIZE]; // 串口1接收分配缓存static INT8U COMM1_MEM_SEL Comm1RxBufCtr; // 串口1接收数据个数计数器static INT8U COMM1_MEM_SEL Comm1RxInIx; // 串口1接收数据入缓存位置索引static INT8U COMM1_MEM_SEL Comm1RxOutIx; // 串口1接收数据出缓存位置索引static BOOL bComm1CanSend; // 串口1发送忙标志0=不忙1=忙static INT8U COMM1_MEM_SEL Comm1TxBuf[COMM1_TXD_SIZE]; // 串口1发送分配缓存static INT8U COMM1_MEM_SEL Comm1TxBufCtr; // 串口1发送数据个数计数器static INT8U COMM1_MEM_SEL Comm1TxInIx; // 串口1发送数据入缓存位置索引static INT8U COMM1_MEM_SEL Comm1TxOutIx; // 串口1发送数据出缓存位置索引/******************************************************************************************* ******** 局部函数******************************************************************************************** ******//******************************************************************************************* ******** COMM1相关函数集******************************************************************************************** ******/#define CR PutString("\r\n") //发送一个回车换行#define NUL putstring("{post.content}") //发送一个空格/******************************************************************************************* ******** 功能: COMM1 工作状态初始化* 入口: 'baud' 波特率最大波特率为实际硬件能支持的波特率和数据处理能力设置* 'parity' 奇偶效验none(无) even(偶校验) odd(奇校验)* 'bits' 数据位为5,6,7,8,9位* 'stops' 停止位为1,2位* 返回: 1> COMM_ON_ERR 串口设置没有错误* 2> COMM_BAD_BUAD 错误的波特率* 3> COMM_BAD_MODE 错误的工作模式* 说明:******************************************************************************************** *******/#if (COMM1_UNIT_EN > 0 && COMM1_RXD_EN > 0) || ( COMM1_UNIT_EN > 0 && COMM1_TXD_EN > 0)INT8U Comm1CfgPort (INT32U baud, INT8U parity, INT8U bits, INT8U stops){INT8U UCSRC_TEMP; //UBRRH和UCSRC的读写操作很特殊COMM_ENTER_CRITICAL();#if COMM_MODE == 0UBRRH = (INT8U)((MCU_Fosc/16/(baud+1))>>8); // 设异步正常模式串口波特率UBRRL = (INT8U)((MCU_Fosc/16/(baud+1)));UCSRA = MPCM_MODE; // 多机模式设定#elif COMM_MODE == 1UBRRH = (INT8U)((MCU_Fosc/8/(baud+1))>>8); // 设异步倍速模式串口波特率UBRRL = (INT8U)((MCU_Fosc/8/(baud+1)));UCSRA = BIT(U2X)|MPCM_MODE; // 倍速发送和多机模式设定#elif COMM_MODE == 2UBRRH = (INT8U)((MCU_Fosc/2/(baud+1))>>8); // 设同步模式串口波特率UBRRL = (INT8U)((MCU_Fosc/2/(baud+1)));UCSRA = MPCM_MODE; //#endif// 接收中断,发送中断,数据寄存器空中断,同步时钟极性,发送使能,接收使能设定UCSRB =RXCIE_MODE|TXCIE_MODE|UDRIE_MODE|UCPOL_MODE|BIT(RXEN)|BIT(TXEN);switch (bits) {case 5 :UCSRC_TEMP = BIT(URSEL)|UMSEL_MODE;break;case 6:UCSRC_TEMP = BIT(URSEL)|UMSEL_MODE|BIT(UCSZ0);break;case 7:UCSRC_TEMP = BIT(URSEL)|UMSEL_MODE|BIT(UCSZ1);break;case 8 :UCSRC_TEMP = BIT(URSEL)|UMSEL_MODE|BIT(UCSZ1)|BIT(UCSZ0);break;case 9 :SETBIT(UCSRB,BIT(UCSZ2));UCSRC_TEMP = BIT(URSEL)|UMSEL_MODE|BIT(UCSZ1)|BIT(UCSZ0);break;default:UCSRC_TEMP = BIT(URSEL)|UMSEL_MODE|BIT(UCSZ1)|BIT(UCSZ0); //默认为8BITbreak;}if (stops == 2){ // 设停止位SETBIT(UCSRC_TEMP,(BIT(URSEL)+BIT(USBS)));}switch (parity) {case none : // 无校验break;case 1: // 系统保留break;case even:SETBIT(UCSRC_TEMP,(BIT(URSEL)+BIT(UPM1))); // 偶校验break;case odd :SETBIT(UCSRC_TEMP,(BIT(URSEL)+BIT(UPM1)+BIT(UPM0))); // 奇校验break;default: //默认为无校验break;}UCSRC = UCSRC_TEMP;COMM_EXIT_CRITICAL();return (COMM_NO_ERR);}#endif/******************************************************************************************* ******** 功能: 串口接收中断响应函数* 入口: 无* 返回: 无* 说明: 1> 使用串口中断前先用Comm1CfgPort 函数配置好波特率工作模式等信息* 2> 使用串口中断前再调用Comm1VarInit 函数初始化各种变量否则工作可能出错* 3> 如果使能串口0接收部分则需要配置接收缓存此缓存不能太小发送方的数据根据波特率的关系处* 理发送速度和MCU的处理速度(串口进缓存24MHz <40us)决定发送速度不能太快否则后面的数据会* 抛弃造成数据的丢失* 4> 如果使能串口发送部分需要配置好发送缓存此发送缓存的大小不做特殊要求但太小会影响本地* 的MCU的处理本地事务的能力(特别是前后模式的程序和波特率低的情况)* 5> 如果是在OS中使用可以启用通知函数给串口接收分析任务分析接收的数据参考程序中屏蔽的函数* 6> 中断响应的速度与COMM_MEM_SEL和高优先级中断的响应时间有关如果接收数据很快可以加DISABLE命令******************************************************************************************** ******/ISR(SIG_UART_RECV){//COMM_ENTER_CRITICAL(); // 进入临界处理if (Comm1RxBufCtr < COMM1_RXD_SIZE) {Comm1RxBufCtr++; // 接收缓存计数器加1Comm1RxBuf[Comm1RxInIx++] = UDR; // 接收到的数据进缓存if (Comm1RxInIx >= COMM1_RXD_SIZE) {Comm1RxInIx = 0;}}//COMM_EXIT_CRITICAL(); // 退出临界}/******************************************************************************************* ******** 功能: 串口发送完中断响应函数* 入口: 无* 返回: 无* 说明: 1> 使用串口中断前先用Comm1CfgPort 函数配置好波特率工作模式等信息* 2> 使用串口中断前再调用Comm1VarInit 函数初始化各种变量否则工作可能出错* 3> 如果使能串口发送部分需要配置好发送缓存此发送缓存的大小不做特殊要求但太小会影响本地* 的MCU的处理本地事务的能力(特别是前后模式的程序和波特率低的情况)* 4> 如果是在OS中使用可以启用通知函数给串口接收分析任务分析接收的数据参考程序中屏蔽的函数* 5> 中断响应的速度与COMM_MEM_SEL和高优先级中断的响应时间有关如果接收数据很快可以加DISABLE命令******************************************************************************************** ******/ISR(SIG_UART_TRANS){//COMM_ENTER_CRITICAL(); // 进入临界#if COMM_DA TAFREE_ISR_EN == 0if (Comm1TxBufCtr > 0) { // 检查发送消息缓存区是否为空不为空则继续发数据Comm1TxBufCtr--; // 缓存计数器减1UDR = Comm1TxBuf[Comm1TxOutIx++]; // 读走一个数据到发送寄存器,自动清发送中断标志if (Comm1TxOutIx >= COMM1_TXD_SIZE) {Comm1TxOutIx = 0;}} else {bComm1CanSend = 0; // 发送标志为0表示可以直接发送信息}#endif//COMM_EXIT_CRITICAL(); // 退出临界}/******************************************************************************************* ******** 功能: 串口发送数据寄存器空中断函数* 入口: 无* 返回: 无* 说明: 数据寄存器空UDRE标志位为1表示发送缓冲区可以接受一个新的数据******************************************************************************************** ******/#if COMM_DA TAFREE_ISR_EN > 0ISR(SIG_UART_DATA){//COMM_ENTER_CRITICAL(); // 进入临界if (Comm1TxBufCtr > 0) { // 检查发送消息缓存区是否为空不为空则继续发数据Comm1TxBufCtr--; // 缓存计数器减1UDR = Comm1TxBuf[Comm1TxOutIx++]; // 读走一个数据到发送寄存器,自动清发送中断标志if (Comm1TxOutIx >= COMM1_TXD_SIZE) {Comm1TxOutIx = 0;}} else {CLRBIT(UCSRB,BIT(UDRIE)); // 数据发送完,清数据寄存器中断使能位bComm1CanSend = 0; // 发送标志为0表示可以直接发送信息}//COMM_EXIT_CRITICAL(); // 退出临界}#endif/******************************************************************************************* ************** 功能: 发送的数据进入发送缓存* 入口: 'Data' 进入缓存的消息数据* 返回: 1> COMM_TXD_FLOODL 发送数据进入缓存满(失败)* 2> COMM_TXD_OK 发送数据进入缓存OK* 说明: 无******************************************************************************************** ************/#if COMM1_UNIT_EN > 0 && COMM1_TXD_EN > 0INT8U Comm1TxInBuf (INT8U Data){INT8U err;err = COMM_TXD_FLOOD; // 设置发送缓存为满COMM_ENTER_CRITICAL(); // 进入临界if (!bComm1CanSend) { // 判断串口直接发送允许标志位0为允许bComm1CanSend = 1; // 设置为忙UDR = Data; // 发送出数据#if COMM_DA TAFREE_ISR_EN > 0SETBIT(UCSRB,BIT(UDRIE)); // 数据发送开始,置数据寄存器中断使能位#endifCOMM_EXIT_CRITICAL(); // 退出临界return (COMM_TXD_OK); // 返回代码为发送OK}if (Comm1TxBufCtr < COMM1_TXD_SIZE) { // 处理发送缓存计数器err = COMM_TXD_OK; // 设置发送缓存为正常Comm1TxBufCtr++; // 发送缓存计数器加1Comm1TxBuf[Comm1TxInIx++] = Data; // 来不及发送的数据进发送缓存if (Comm1TxInIx >= COMM1_TXD_SIZE) { // 处理发送进缓存计数器Comm1TxInIx = 0; // 复位发送进缓存计数器}}COMM_EXIT_CRITICAL(); // 退出临界开始准备发送多字符return (err);}#endif/******************************************************************************************* ************** 功能: COMM1 发送1 BYTE数据* 入口: 'Date' 发送的数据* 返回: 1> COMM_TXD_OK 发送数据OK* 2> COMM_TXD_FALSE 发送失败一般是发送缓存已满* 说明: 1> UDR发送寄存器为空时直接把要发送的数据放到发送缓存* 2> UDR发送寄存器为忙时来不及发的数据进入到发送缓存* 3> 发送缓存满时直接返回发送失败******************************************************************************************** ************//*INT8U Comm1TxPutChar (INT8U Data){COMM_ENTER_CRITICAL(); // 进入临界if (!bComm1CanSend) { // 判断串口直接发送允许标志位0为允许bComm1CanSend = 1; // 设置为忙UDR = Data; // 发送出数据COMM_EXIT_CRITICAL(); // 退出临界return (COMM_TXD_OK); // 返回代码为发送OK}if (Comm1TxBufCtr >= COMM1_TXD_SIZE) { // 判断发送缓存计数器是否为最大发送缓存COMM_EXIT_CRITICAL(); // 是退出临界不处理return (COMM_TXD_FALSE); // 发送缓存满返回代码为发送失败} else {Comm1TxInBuf(Data); // 来不及发送的数据一直等到进入发送缓存COMM_EXIT_CRITICAL(); // 退出临界return (COMM_TXD_OK); // 返回代码为发送OK}}*//******************************************************************************************* ************** 功能: COMM1 发送N BYTE数据* 入口: 'p' 指向发送消息的指针* 'len' 发送数据的长度* 返回: 返回实际发送的数据长度* 说明: 1> 如果是发送失败则直接返回这样在多任务里面就可以延时N个周期再尝试重发数据这样就不会在这里* 多等更多的时间但这种情况不是绝对的根据波特率是有很大的关系* 2> 建议发送时的缓存最好保证>=即将发送的数据长度数据流之间能留一定的时间间隔保证发送数据* 3> 发送的数据长度大于实际能缓存的长度时波特率是影响其工作效率的主要因素MCU中的RAM一般比较小******************************************************************************************** ************/INT8U Comm1TxPutsChar (INT8U *s, INT8U len){INT8U i;//COMM_ENTER_CRITICAL(); // 进入临界i = COMM1_TXD_SIZE - Comm1TxBufCtr; // 实际还有多少可用缓冲区//COMM_EXIT_CRITICAL(); // 退出临界if (i > len){ // 发送数据长度小于可用缓冲区时,i = len; // 所有数据能全部发送成功}else{len = i;}while (i--) { // 发送数据处理Comm1TxInBuf(*s); // 发送的数据进入发送缓存s++; // 数据指针加1}return (len); // 返回实际发送的数据长度}/******************************************************************************************* ************** 功能: 串口1读1则数据* 入口: 'err' 返回错误信息的指针* 返回: 1> 读到的数据* 2> err=COMM_RXD_EMPTY 接收缓存没有数据* 3> err=COMM_RXD_OK 正确在接收缓存读到数据* 说明: 1> 在调用此函数前最好用Comm1RxGetNMsgs函数检查一下接收缓存里面有没有信息* 2> 如果不按1>的用法用则要对返回的错误代码分析******************************************************************************************** ************/INT8U Comm1RxGetChar (INT8U *Data){INT8U err = COMM_RXD_EMPTY; // 返回代码为接收为空COMM_ENTER_CRITICAL(); // 进入临界if (Comm1RxBufCtr > 0) { // 检测接收缓存是否有数据Comm1RxBufCtr--; // 有数据计数器减1*Data = Comm1RxBuf[Comm1RxOutIx++]; // 取出数据err = COMM_RXD_OK; // 返回代码为读数据正确if (Comm1RxOutIx >= COMM1_RXD_SIZE) { // 检查出数据计数器是否大于最大接收缓存Comm1RxOutIx = 0; // 是复位出数据计数器}}COMM_EXIT_CRITICAL(); // 退出临界return (err);}/******************************************************************************************* ************** 功能: 检测接收缓存中的数据个数* 入口: 无* 返回: 缓存中的数据个数* 说明: 无******************************************************************************************** ************/INT8U Comm1RxGetNMsgs (void){INT8U counter;COMM_ENTER_CRITICAL(); // 进入临界counter = Comm1RxBufCtr; // 取接收计数器数据COMM_EXIT_CRITICAL(); // 退出临界return (counter); // 返回接收缓存计数}/******************************************************************************************* ************** 功能: 一次串口1读N则数据* 入口: 'p' 返回数据信息的指针* 'len' 读的数据长度< COMM1_RXD_SIZE* 返回: 1> COMM_RXD_EMPTY 读数据为空一般是len为空或接收缓存中没有数据* 2> COMM_RXD_FALSE 错误读数据一般为len大于数据接收缓存中的数据* 3> COMM_RXD_OK 数据正确读到* 说明: 1> 对于返回参数2> 可以使用Comm1RxGetNMsgs 先取得缓存中的数据个数再一次读走******************************************************************************************** ************/#if COMM1_UNIT_EN > 0 && COMM1_RXD_EN > 0 && COMM1_GETS_EN > 0INT8U Comm1RxGetsChar (INT8U *s, INT8U len){COMM_ENTER_CRITICAL(); // 进入临界处理Comm1RxBufCtrif ((len == 0) || (Comm1RxBufCtr == 0)) { // 检查数据长度和接收缓存是否为空COMM_EXIT_CRITICAL(); // 退出临界return (COMM_RXD_EMPTY); // 返回代码为接收空}if (len > Comm1RxBufCtr) { // 检查读数长度跟实际接收缓存数据个数COMM_EXIT_CRITICAL(); // 退出临界return (COMM_RXD_FALSE); // 返回代码为读数据失败}COMM_EXIT_CRITICAL(); // 退出临界// 必须退出临界以便其他的中断响应否则len大时就会影响中断while (len--) { // 读走len个数据COMM_ENTER_CRITICAL(); // 进入临界处理Comm1RxBufCtr*s++ = Comm1RxBuf[Comm1RxOutIx++]; // 取出数据Comm1RxBufCtr--; // 接收缓存计数器减1if (Comm1RxOutIx >= COMM1_RXD_SIZE) { // 处理接收出数据计数器Comm1RxOutIx = 0; // 复位出数据计数器}COMM_EXIT_CRITICAL(); // 退出临界}return (COMM_RXD_OK); // 返回代码为接收到正确数据}#endif/******************************************************************************************* ************** 功能: 初始化串口1的各种变量* 入口: 无* 返回: 无* 说明: 无******************************************************************************************** ************/void Comm1VarInit (void){#if COMM1_RXD_EN > 0 // 初始化接收的各种变量Comm1RxBufCtr = 0;Comm1RxInIx = 0;Comm1RxOutIx = 0;#endif#if COMM1_TXD_EN > 0 // 初始化发送的各种变量Comm1TxBufCtr = 0;Comm1TxInIx = 0;Comm1TxOutIx = 0;bComm1CanSend = 0; // 串口0寄存器发送忙标志#endif}#endif/******************************************************************************************* ************** End Of File******************************************************************************************** ************/。
AVR串口多机通讯模式的问题
AVR 串口多机通讯模式的问题
在多机通信过程中,所有设备的RS232 接口是并在通信线上的,其中只能有一个设备为主机,其他为从机,通信由主机发起。
数据帧一般采用1 位起始位、9 位数据位,其中第9 位(RXB8)被用作为表征该帧是地址帧还是数据帧。
当帧类型表征位为1 时,表示该帧数据为一个地址帧;当帧类型表征位为0 时,表示这个帧为一个数据帧。
更多信息可以点击:单片机常见问题
在AVR 中,通过设置从机的UCSRA 寄存器中标志位MPCM,可以使能USART 接收器对接收的数据帧进行过滤的功能。
如果使能了过滤功能,从机接收器对接收到的那些不是地址信息帧的数据帧将进行过滤,不将其放入接收缓冲器中,这在多机通信中有效的方便了从机MCU 处理数据帧程序的编写(同标准51 结构相比)。
而发送器则不受MPCM 位设置的影响。
多机通信模式允许多个从机并在通信线路上,接收一个主机发出的数据。
通过对接收到的地址帧中的地址进行解码,确定哪个从机被主机寻址。
如果某个从机被主机寻址,它将接收接下来主机发出的数据帧,而其它的从机将忽略数据帧,直到再次接收到一个地址帧。
(从机地址是由各个从机自己的软件决定的)。
对于在多机通信系统中的主机MCU,可以设置使用9 位数据帧结构(UCSZ=7)。
当发送地址帧时,置第9 位为1;发送数据帧时,置第9 位为0。
AVR单片机串口通信程序
AVR单片机串口通信程序单片机的串口在很多时候都是一个有用的通信接口,比如要修改单片机内部的一些变量,就可以直接使用串口通信,将参数发送到单片机,就省去了重新编译下载的麻烦。
AVR单片机的串口通信功能可谓强大啊,下面就简单说下我在学习时的一些经验。
实验板是AVR-ATMEGA128A单片机,晶振8MHz。
1、初始化:设置波特率前,要关闭 USART0 的所有使用,包括使能和中断。
2、设置 UCSR0A: UCSR0A 能写的有Bit0,Bit1,Bit6,其他 5 位为状态位.我们一般使用的有Bit1-U2X0,当这一位为 1 时,波特率的分频因子从 16 降到 8,能够有效的将异步通信模式的传输速率加倍,但是这一位仅对异步操作有影响,使用同步操作时应将此位清零。
3、设置 UCSR0C: Bit6-UMSEL0:USART0 的模式选择0为异步模式,1为同步模式。
Bit5:4-UPM01:0:奇偶校验模式,00 禁止,01,保留,10 偶校验,11奇校验。
Bit3-USBS0:停止位的选择 0-停止位为1bit,1 停止位为 2bitsBit2:1-UCSZ01:0:字符长度当 UCSZ02 为0时:00 表示 5 位,01 表示 6 位,10 表示7 位,11表示 8 位。
当 UCSZ02 为 1 时,11 表示 9 位(UCSZ02 为UCSR0B 里的一位寄存器)。
4、设置 UBRR: UBRR 的设置和这些参数有关:U2X0,CPU 频率,波特率5、然后就是设置 UCSR0B:Bit7-RXCIE0 为接收结束中断使能,Bit6-TXCIE0 为发送结束中断使 ,Bit4-RXEN0 为接收使能,Bit3-TXEN0 为发送使能。
一般情况下,接收使用中断方式,所以使用接收结束中断使能。
下面是源代码:/** usart.c** Created: 2011/7/2 15:48:36* Author: YIN*/#include ;#include ;#include ;volatile unsigned char temp; void init(){UCSR0B=0x00;UBRR0H=0x00;UBRR0L=51;UCSR0A=0x00;UCSR0C=0x06;UCSR0B=0x98;sei();DDRF=0xff;PORTF=0xff;DDRD=0xf0;DDRA=0xff;}void delay(){unsigned int i;i=100;while(i--);}int main(void){init();while (1); //等待中断}SIGNAL(SIG_UART0_RECV) //将上位机发送的数据发送回上位机显示{temp=UDR0;PORTA=~temp;UDR0=temp;}部分内容摘自网络,希望对大家有帮助!。
AVR单片机的串行通信
whl () i e 1 {
Trn mi ip taa ; a s t( ud t) n
送 ;读寄存器时将读取移位寄存 器接收缓 冲区的值 。
};
}
3 实例 分析
现 将 A 9 S 5 5与 A 9 S 4 4两 个 系 统 相 连来 进 行 数 据 T 0 83 T043
口也 同样 允 许 在 A m g 列 单 片 机 和 外 设 或 其 他 A R 系 列 T ea系 V
单片机之 间高速 同步数据传输 。A 9 T 0系列 S I P 特征如下 :
()采 用 全 双 T 模式 ,3线 同步 进 行 数据 传 输 。 1 () 可 以 当作 主 机或 从 机 上 作 。 2 () 可 配 置 为 MS 3 B方 式 或 L B方 式 。 S
Ke r s VR sn l — h p; P S r l o y wo d :A ig e c i S I; e a mmu ia in i c nc t o
l 前 言
A R单 片 机 是 由美 国 A M E V T L公 司 19 年 开 始 逐 步设 计 97
SI P 既可 以工作在 主模式下 ,也可 以 : 【 作在从模式下。当工作 在主模式下 时 ,每发送 或接收一位数 据 ,都需 要一次 时钟作 用 ;而 当工作 在从模式下 时 ,每次接 收到时钟信 号之后 才进 行一位数据 的发送或接 收。S I P 主机— —从机的互联如 图, 1所 示, 系统包括两个移位寄存器和一个主机时钟发 生器 。将 需要 的从机 的 s s引脚拉低 ,从而使主机启动一次通信过程 。主机 和 从机 将需 要 发送 的数 据放 入 相应 的移 位 寄存 器 。主 机在
S K 引 脚 上 产 生 时 钟 脉 冲 以 交 换 数 据 。 S K引 脚 是 主 机 模 式 C C 时 的时 钟 输 出 以及 从 机 模 式 的 时钟 输 入 。 主 机 数 据 从 主 机 的 MO I 出 , 由从 机 的 MO I 人 ; 从 机 数 据 由从 机 MIO 移 S移 S移 S 出 , 由主机 的 M S 移入 。 主 机通 过将 从 机 的 S IO s拉 高实 现 与
AVR单片机串口操作程序
AVR单片机串口操作程序#include#include#include#include#include#define FOSC 8000000 //mcu工作时钟频率typedef unsigned int uint16;typedef unsigned char uchar8;uchar8DoubleIRData[25]={0x64,0x00,0x20,0x04,0x40,0x00,0 ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; //双红外发射数据取PD2作为驱动远程红外发射//uchar8SingleIRData[25]={0x60,0x00,0x04,0x00,0x04,0x00,0 ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} //取PD2作为驱动远程红外发射 //取PD3驱动红外发射uchar8 BitCount=0; //载波计数uchar8 BetyCount=0; //位计数volatile uchar8 UsartDataBuff=0;volatile uchar8 ChargeFlag=0,LED_Count;volatile uchar8 SYSCount=0;volatile uint16 ADCCurrent1=0; //AD0转换结果电压检测volatile uint16 ADCCurrent3=0; //AD3结果转换电流检测void Port_Init(void){DDRA = 0b00000000; //AD采样 PA0 PA1PORTA = 0b00000000; //PA口:初始化0//PB PC 没有使用DDRD = 0b11111110; //PD2 为远程红外发射 PD3 和PD4 状态指示灯,P3未充电 P4表示充电 PD5和PD6 双红外近区发射 PD7 开关充电使能PORTD = 0b00000011; //初始化输出为0 其中USART 接收口上拉高电平等待接收中断}void ADC_Init(void){ADCSRA=0x00; //ADC控制状态寄存器ADMUX =0x40; //ADC 多工选择寄存器参考电压为AVCC,其中AREF 引脚外加滤波电容数据右对齐结果选择0通道ACSR =(1;=66)//波特率=1/(0.00002625S*66)=577 {BetyCount++;if(BetyCount>;=20)//25{//TCCR0=0;//TCCR2=0;BetyCount=0;}BitCount=0;}}ISR(TIMER1_COMPA_vect){SYSCount=1;}void Usart_send(uchar8 data){while(!(UCSRA&(1;=200)//电压大于开始供电//200 {PORTD|=(1<<PD7);ChargeFlag=1;}else{ChargeFlag=0;}}//UsartDataBuff=Usart_Read(); if(UsartDataBuff){}}//i=((uchar8 *)(&k))[0];//j=((uchar8 *)(&k))[1];}}。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
A VR单片机串口多机通讯程序[日期:2010-09-01 ] [来源:本站原创作者:admin] [字体:大中小] (投递新闻)在多机通信过程中,所有设备的RS232接口是并在通信线上的,其中只能有一个设备为主机,其他为从机,通信由主机发起。
数据帧一般采用1位起始位、9位数据位,其中第9位(RXB8)被用作为表征该帧是地址帧还是数据帧。
当帧类型表征位为“1”时,表示该帧数据为一个地址帧;当帧类型表征位为“0”时,表示这个帧为一个数据帧。
在A VR中,通过设置从机的UCSRA寄存器中标志位MPCM,可以使能USART接收器对接收的数据帧进行过滤的功能。
如果使能了过滤功能,从机接收器对接收到的那些不是地址信息帧的数据帧将进行过滤,不将其放入接收缓冲器中,这在多机通信中有效的方便了从机MCU处理数据帧程序的编写(同标准51 结构相比)。
而发送器则不受MPCM位设置的影响。
多机通信模式允许多个从机并在通信线路上,接收一个主机发出的数据。
通过对接收到的地址帧中的地址进行解码,确定哪个从机被主机寻址。
如果某个从机被主机寻址,它将接收接下来主机发出的数据帧,而其它的从机将忽略数据帧,直到再次接收到一个地址帧。
(从机地址是由各个从机自己的软件决定的)。
对于在多机通信系统中的主机MCU,可以设置使用9位数据帧结构(UCSZ=7)。
当发送地址帧时,置第9位为“1”;发送数据帧时,置第9位为“0”。
在这种情况下,从机也必须设置成接收9位数据帧结构。
多机通信方式的数据交换过程如下:1)设置所有从机工作在多机通信模式(MPCM=1)。
2) 通信开始是由主机先发送一个地址帧,如8位数据为0X01(1号从机地址),第9位=“1”,呼叫1号从机。
3)所有从机都接收和读取该主机发出的地址帧。
在所有从机的MCU中,RXC标志位被置位,表示接收到地址帧。
4)每一个从机MCU读UDR寄存器,并判断自己是否被主机寻址。
如果被寻址,清UCSAR寄存器中的MPCM位,等待接收数据;否则保持MPCM为“1”,等待下一个地址帧的接收(该步应由用户软件处理实现):A)作为1号从机的MCU处理过程为:收到地址帧后,判定读取UDR数据0X01为自己的地址,将MPCM位置“0”,接收之后所有主机下发的数据帧,直到下一个地址帧为止。
B)其它从机MCU的处理过程:收到地址帧后,判定读取UDR数据0X01不是自己的地址,将MPCM位置“1”,这样他们将忽略主机随后发送的数据帧,直到主机再次发送地址帧。
5)当被寻址的从机MCU接收完最后一个数据帧后,将MPCM位置位,等待下一个地址帧的出现(该步也应由用户软件处理实现),然后从步骤2开始重复。
[转]例子;通讯规则:1:时钟7.3728 MHz/波特率9600/9个数据位/奇校验/1个停止位/硬件多机通讯功能/ 2:通讯连接采用硬件MAX485,双向单工3:每个上行/下行的数据包的字节个数都是一样的(通讯数据量)4:每个上行/下行的数据包都采用CRC8校验5:数据接收采用中断+查询的方式6:总是由主机向从机发送一个数据包,从机收到数据包后向主机回复一个数据包7:不管是主机还是从机,如果收到的数据包有任何错误,都将丢弃该数据包,等效于没有接收8:从机之间不能相互通讯,必须通过主机才能交换数据9:无效地址是0,主机地址是1,从机地址是2.3.4......广播地址是255*/#include <mega8.h>#include <delay.h>#include <usart.h>#include <crc8.h> //CRC校验函数就在这个文件里面#define amount 10 //设定通讯数据量(包括1个地址帧,n个数据帧,1个校验帧)unsigned char send[amount]; //发件箱unsigned char inbox[amount]; //收件箱unsigned char n=0; //记忆中断次数//--------------------------------------------------------------------interrupt[12] Rxd_isr(void) //接收中断{unsigned char ERROR=0;if( UCSRA&4 || UCSRA&16 ) ERROR=1; //奇偶效验错误或者帧错误就记录下来inbox[n]=UDR; //保存到收件箱n++; //记忆中断次数if(ERROR) inbox[0]=0; //如果通讯有错,收件箱的地址帧就标记成无效地址0}//---------------------------------------------------------------------void main(void){usart_init(); //串口初始化UCSRA=0; //主机关闭地址筛选功能(多机通讯功能) #asm("sei") //打开全局中断while(1){//-------------与从机2对话,与其他从机对话与下面的程序类似-------------------n=0; //中断次数清0inbox[0]=0; //收件箱地址清0//请更新准备发送的数据//send[1]=?//......//send[n]=?send[0]=2; //改变这个地址就可以实现与某个从机对话send[amount-1]=crc8(send,amount-1); //计算发件箱的crc8校验码usart_out(send,amount); //将发件箱的数据send[]发送出去;//等待,从机接收到数据后会回复数据的,如果是10个字节数据量,不能少于13ms!!!//这个时间由人工计算,要考虑从机由于各种中断延长回复时间的可能delay_ms(15);//if(n<3) 如果接收到的数据还不到3个,那么就是通讯线路故障//如果收件箱已经收到amount个数据,并且crc8校验成功就...if(n==amount && inbox[amount-1]==crc8(inbox,amount-1)){if(inbox[0]==1) //如果收件箱地址帧属于本机就运行下面的测试代码{DDRD.3=1;PORTD.3=1; delay_ms(10);PORTD.3=0; delay_ms(990);}if(inbox[0]==255){//请在这里添加收到广播数据的处理程序}}}} //end------------------------------------------------------------从机------------------------------------------------------------#include <mega8.h>#include <usart.h>#include <crc8.h>#define amount 10 //设定通讯数据量(包括1个地址帧,n个数据帧,1个校验帧)#define address 2 //请在这里设定本机地址unsigned char send[amount]; //发件箱unsigned char inbox[amount]; //收件箱unsigned char n=0; //记忆中断次数interrupt[12] Rxd_isr(void) //接收中断{unsigned char ERROR=0;if( UCSRA&4 || UCSRA&16 ) ERROR=1; //记录奇偶效验错误或者帧错误inbox[n]=UDR; //把接收到的数据保存到收件箱n++; //记忆接收的次数if(ERROR) //如果通讯有错....{n=0; //接收计数清0inbox[0]=0; //把地址改为无效地址0UCSRA|=0x01; //重新打开接收器的地址帧筛选功能}//如果地址匹配本机或者是广播地址就关闭地址筛选(多机通讯)功能if(inbox[0]==address ||inbox[0]==255) UCSRA&=254;if(n==amount) //接收到amount个数据以后...{n=0; //接收计数清0UCSRA|=0x01; //重新打开接收器的地址帧筛选功能if(inbox[amount-1]==crc8(inbox,amount-1)) //如果crc8校验正确就...{if(inbox[0]==address) //如果地址匹配本机就回复数据{send[0]=1; //发件箱地址指向主机send[amount-1]=crc8(send,amount-1);//产生发件箱的crc8校验码usart_out(send,amount); //发送发件箱的数据包send[]//请在这里备份你的收件箱信息}if(inbox[0]==255) //如果是广播地址就...{//请在这里添加你的代码//收到广播数据请不要回复}}}}void main(void){usart_init();#asm("sei")while (1){//send[1]=?//......//send[n]=?};}---------------------------------------------------------------------------------usart.h文件---------------------------------------------------------------------------------//波特率9600/9个数据位/1个停止位/奇校验/收发开启/接收中断void usart_init(void){UCSRA=0x01;UCSRB=0x9C;UCSRC=../../0xB6;UBRRH=0x00;UBRRL=47;PORTD.4=0; //MAX485平时工作在接收状态DDRD.4=1;}//-----------------------------------------------------------//从数组datas[]的首地址开始发送amount个数据,其中第0个数据是地址帧,其他是数据帧void usart_out(unsigned char *datas,unsigned char n){unsigned char i=0;PORTD.4=1; //使MAX485处于发送状态while(i<n) //一共发送amount个数据{if(i==0) UCSRB|=1; else UCSRB&=254;UDR=*(datas+i); //装载数据开始发送while((UCSRA&64)==0); //等待发送结束UCSRA|=64; //清除发送结束标志i++; //发送次数统计}PORTD.4=0; //使MAX485处于接收状态}---------------------------------------------------------------------------------crc8校验程序---------------------------------------------------------------------------------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++;}return(crc);}参考链接:/news/2010-09/2299.htm。