近日,应网友的要求,做了两个M16通过TWI进行通信的实验,现将相关代码公布如下,欢迎各位朋友拍砖!
硬件联接:第一个M16实验板通过232与PC通信,设为主机。第二个M16采用的是本站学习板,并设为从机,从机地址在这里设为0x06(相当于24C02的0xA0)。两板间通过三条杜帮线将SCL、SDA、GND对应联接起来。其中SCL、SDA两管脚接4.7K上拉电阻。
实验方法:PC机上的串口调试助手按要求发送数据到主M16,主M16通过TWI传送到从M16,从M16将收到的数据在数码管上显示,同时将显示内容传回主M16并回送PC显示。
串口发送到主M16的控制命令为8字节,十六进制数据帧格式:第一字节0X55,帧头;第二字节0X06,从机地址;第三字节0X00,从机子地址(即从哪位数码管开始),范围为0-3;第四、五、六、七字节为数据,对应随后数码管的位显示,范围为0-9、A-F;第八字节0XAA,帧结束标志。
主机程序:
/************************************
* M16通过TWI向M16发送数据的程序 *
* 功 能:M16通过TWI读写M16 *
* 建立日期:2008年11月04日 *
* 设 计 者:铜河 *
* 版 本:V1.0 *
* 修改日期:2008年11月04日 *
* 主控芯片:ATmega16 *
* 时钟频率:外部晶体7.3728MHz *
* 编 译 器:ICCAVR6.31A *
************************************/
#include <iom16v.h>
#include <macros.h>
//-----------TWI状态定义-------------
//MT为主方式发送,MR为主方式接收
#define START 0x08 //启动TWI的响应
#define RE_START 0x10 //重新启动TWI的响应
#define MT_SLA_ACK 0x18 //发送地址已响应
#define MT_SLA_NOACK 0x20 //发送地址已非响应
#define MT_DATA_ACK 0x28 //发送数据已响应
#define MT_DATA_NOACK 0x30 //发送数据已非响应
#define MR_SLA_ACK 0x40 //主接收地址返应答
#define MR_SLA_NOACK 0x48 //主接收地址返非应答
#define MR_DATA_ACK 0x50 //主接收数据返应答
#define MR_DATA_NOACK 0x58 //主接收数据返非应答
//常用TWI主模式写和主模式读
#define Start() (TWCR=(1<<TWINT)|(1<<TWSTA)|(1<<TWEN))
#define STOP() (TWCR=(1<<TWINT)|(1<<TWSTO)|(1<<TWEN))
#define WAIT() {while(!(TWCR&(1<<TWINT)));} //等待操作完成
#define TESTACK() (TWSR&0xF8) //读取状态数据
#define SETACK() (TWCR|=(1<<TWEA)) //应答
#define SETNOACK() (TWCR&=~(1<<TWEA)) //非应答
#define TWI() (TWCR=(1<<TWINT)|(1<<TWEN)) //启动TWI读方式
#define WRITE8BIT(x) {TWDR=(x);TWCR=(1<<TWINT)|(1<<TWEN);} //发送8位数据
unsigned char uart_buff[7]={0}; //串口接收缓冲
unsigned char xs[4]; //发送缓冲
unsigned char SLA_ADDR; //需读写的从器件地址:从串口接收的数据中获取
/********************************
* 函数名称: void port_init(void)*
* 函数功能:端口初始化 *
********************************/
void port_init(void)
{
PORTA = 0xFF;
DDRA = 0xFF;
PORTB = 0x00;
DDRB = 0xFF;
PORTC = 0x00;
DDRC = 0xFF;
PORTD = 0x00;
DDRD = 0x00;
}
/************************************
* 函数名称: void delay_ms(uint i) *
* 函数功能:延时函数 *
* 晶振频率:7.3728MHZ *
* 实际延时:i mS *
************************************/
void delay_ms(unsigned int i)
{
unsigned int a;
for(;i;i--)
{
for(a=1055;a;a--)
{;}
}
}
/************************************
* 函数名称: void timer1_init(void) *
* 函数功能:定时器1初始化 *
* 预分频值:64 *
* 工作方式:溢出中断 *
* 定时时间:500mSec *
* 时钟频率:外部晶体 7.3728MHz *
************************************/
void timer1_init(void)
{
TCCR1B = 0x00;
TCNT1H = 0x1F;
TCNT1L = 0x01;
TCCR1A = 0x00;
TCCR1B = 0x03;
}
/************************************
* 定时器1溢出中断入口 *
************************************/
#pragma interrupt_handler timer1_ovf_isr:iv_TIMER1_OVF
void timer1_ovf_isr(void)
{
TCNT1H = 0x1F;
TCNT1L = 0x01;
PORTC ^= 1<<3; //LED闪灯
}
/************************************
* 函数名称: void twi_init(void) *
* 函数功能:TWI 初始化 *
* 预分频值:1 *
* 工作方式:主机方式 高速 *
* 时钟频率:外部晶体 7.3728MHz *
************************************/
void twi_init(void)
{
TWCR = 0x44;
}
/************************************
* 函数功能:将指定数据写入指定地址 *
* 入口参数:地址、数据 *
* 出口参数:操作成功1,不成功0 *
************************************/
unsigned char iic_write(unsigned char addr,unsigned char data)
{
unsigned char m;
Start(); //启动IIC
WAIT();
WRITE8BIT(SLA_ADDR); //写从器件地址和写方式
WAIT();
WRITE8BIT(addr); //写子地址
WAIT();
WRITE8BIT(data); //写数据
WAIT();
STOP(); //停止IIC
delay_ms(10); //延时等待
return 0;
}
/************************************
* 函数功能:从指定地址读取数据 *
* 入口参数:地址 *
* 出口参数:成功返回数据,不成功0 *
************************************/
unsigned char iic_read(unsigned char addr)
{
unsigned char temp,m;
Start(); //启动IIC
WAIT();
WRITE8BIT(SLA_ADDR); //写从器件地址和写方式
WAIT();
if(TESTACK()!=MT_SLA_ACK)return 0;
WRITE8BIT(addr); //写子地址
WAIT();
if(TESTACK()!=MT_DATA_ACK)return 0;
Start(); //IIC重新启动
WAIT();
if(TESTACK()!=RE_START)return 0;
WRITE8BIT(SLA_ADDR+1); //写从器件地址和读方式
WAIT();
if(TESTACK()!=MR_SLA_ACK)return 0;//应答
TWI(); //启动主IIC读方式
WAIT();
if(TESTACK()!=MR_DATA_NOACK)return 0;//非应答
temp = TWDR; //读取接收到的数据
STOP(); //停止IIC
return temp;
}
主机程序第二部分:
/************************************
* 函数名称: void uart0_init(void) *
* 函数功能:串口UART0初始化 *
* 波 特 率:9600,8,n,1 *
* 时钟频率:外部晶体 7.3728MHz *
************************************/
void uart0_init(void)
{
UCSRB = 0x00;
UCSRA = 0x00;
UCSRC = BIT(URSEL) | 0x06;
UBRRL = 0x2F;
UBRRH = 0x00;
UCSRB = 0x98;
}
/****************************************
* 函数名称: void Uart_Transmit(uchar i) *
* 函数功能:串口字节数据发送函数 *
* 工作方式:查询方式 *
* 晶振频率:7.3728MHZ,波特率9600 *
****************************************/
void Uart_Transmit(unsigned char i)
{
UDR = i; //发送数据
while (!(UCSRA & (1<<UDRE))); //等待发送缓冲器为空
}
/***************************************
* 串口接收中断函数 *
***************************************/
#pragma interrupt_handler uart0_rx_isr:12
void uart0_rx_isr(void) //串口接收中断函数
{
unsigned char temp; //变量
static unsigned char count; //接收位置计数
temp = UDR;
switch (count)
{
case 0x00: //启动字节校对,如果对则开始接收数据
if (uart_buff[6] == 0x99) //判断主程序是否处理完前面的数据
{
return ;
}
if (temp == 0x55) //启动字节判定
{
PORTC |= 1<<7;
uart_buff[0] = temp; //提取第一个字节
count ++; //计数值增加
}
break;
case 0x01:
SLA_ADDR = temp;
count ++;
break;
case 0x02:
uart_buff[1] = temp;
count ++;
break;
case 0x03:
uart_buff[2] = temp;
count ++;
break;
case 0x04:
uart_buff[3] = temp;
count ++;
break;
case 0x05:
uart_buff[4] = temp;
count ++;
break;
case 0x06:
uart_buff[5] = temp;
count ++;
break;
case 0x07:
if (temp == 0xAA) //数据校验
{
uart_buff[6] = 0x99; //接收正确,设置标志,等待处理
}
PORTC &=~(1<<7);
count = 0x00; //接收完,计数变量清除
break;
default : //计数位置异常捕获
count = 0x00;
PORTC &=~(1<<7);
break;
}
}
/************************************
* 函数名称: void init_devices(void) *
* 函数功能:器件初始化 *
************************************/
void init_devices(void)
{
CLI();
port_init();
timer1_init();
twi_init();
uart0_init();
MCUCR = 0x00;
GICR = 0x00;
TIMSK = 0x04;
SEI();
}
/***************************
* 主函数 *
***************************/
void main(void)
{
unsigned char m;
init_devices();
while(1)
{
if(uart_buff[6]==0x99) //收到新的串口数据
{
PORTC ^= 1<<5;
for(m=0;m<4;m++) //通过TWI发送4个显示数据
{
iic_write((uart_buff[1]+m),uart_buff[m+2]);
}
uart_buff[6]=0; //处理完毕,串口可接收新数据
delay_ms(50);
for(m=0;m<4;m++)
{
xs[m] = iic_read(m); //读取从机数据
Uart_Transmit(xs[m]); //通过串口发回
}
}
}
}
评论1