📄 spi_2dpj_slave.c
字号:
/*****************************************************
**** AVR SPI总线使用范例(两个mega16) ***
**** 作者: liugangdi ***
**** 编译器:WINAVR20050214 ***
**** 日期:2005.11.15 ***
***********************************************/
/*
从机功能简介:通过SPI实现两机通讯, 采用中断方式实现双全工通讯。
本例用两MEGA16实现,连接为:
MISO----MISO
MOSI----MOSI
SCK ----SCK
/SS ----/SS
将要发送的数据加载到发送缓冲区的函数fill_tx_buffer()
和从接收缓冲区读出数据的函数read_rx_buffer()
注意:从机程序和主机程序基本相同,只是将该单片机该为从同步方式即可,2机运行时,从机先开机等待甲机SPI发送*/
//注: 内部函数_delay_ms() 最高延时 262.144mS@1MHz
// ffor()/while()语句计算延时时间较麻烦。
// 为了使 _delay_ms()函数的延时正确,须在makefile中设定F_CPU为实际的系统时钟频
#include <avr/io.h>
#include <avr/delay.h>
#include <avr/signal.h>
#include <avr/interrupt.h>
#define uint unsigned int
#define uchar unsigned char
#define SPI_RX_BUFFER_SIZE 11
#define SPI_RX_BUFFER_MASK SPI_RX_BUFFER_SIZE - 1
#define SPI_TX_BUFFER_SIZE 11
#define SPI_TX_BUFFER_MASK SPI_TX_BUFFER_SIZE - 1
unsigned char SPI_RxBuf[SPI_RX_BUFFER_SIZE];
volatile unsigned char SPI_RxHead;
unsigned char SPI_TxBuf[SPI_TX_BUFFER_MASK];
volatile unsigned char SPI_TxHead;
uchar Tx_counter,spi_trans_com;
//***************************************************
//七段数码管显示函数
//***************************************************
void disp(unsigned char data)
{ DDRB=0xFF;
DDRA=0xFF;
PORTA&=~(1<<6);
PORTB=data;
}
//***************************************************
// 要发送的数据加载到发送缓冲区的函数fill_tx_buffer()
//***************************************************
void fill_tx_buffer(void)
{
uchar SPI_TxBuf[SPI_TX_BUFFER_MASK]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
}
//***************************************************
// 从接收缓冲区读出数据的函数read_rx_buffer()
//***************************************************
void read_rx_buffer(void)
{
/*for(uint i=1;i<SPI_TX_BUFFER_SIZE;i++)
{disp(SPI_RxBuf[i]);
for (uint k=0;k<50 ;k++) _delay_ms(20) ; //延时
}*/
if(SPI_RxBuf[1]==0xc0&&SPI_RxBuf[2]==0xf9&&SPI_RxBuf[3]==0xa4&&SPI_RxBuf[4]==0xb0&&SPI_RxBuf[5]==0x99
&&SPI_RxBuf[6]==0x92&&SPI_RxBuf[7]==0x82&&SPI_RxBuf[8]==0xf8&&SPI_RxBuf[9]==0x80&&SPI_RxBuf[10]==0x90)
PORTC&=~(1<<5); //如果接收的都正确则灯点亮
}
//******************************************
// SPI 中断服务程序 interrupt [SPI_STC]:11
//******************************************
SIGNAL(SIG_SPI)
{
SPI_RxBuf[SPI_RxHead] = SPDR; //从ISP口读出收到的字节
if (SPI_RxHead == SPI_RX_BUFFER_MASK) //如果是接收帧的最后一个数据
{
SPI_RxHead = 0; //已接收数据还原
spi_trans_com=1; //置接收完成标志
}
else
{
SPI_RxHead++; //已接收数据计数器加1
}
if (Tx_counter) //如果发送缓冲区中有待发的数据
{
--Tx_counter;
SPDR=SPI_TxBuf[SPI_TxHead]; //发送一个字节数据,并调整指针
if (++SPI_TxHead ==SPI_TX_BUFFER_MASK)
{SPI_TxHead = 0;
Tx_counter=SPI_TX_BUFFER_MASK;
}
}
}
//**************************************************************
// SPI 初始化 (MEGA16 PB4——/SS,PB5——MOSI,PB6——MISO,PB7——SCK)
//**************************************************************
void spi_init(void)
{
unsigned char temp;
DDRB = 0xB0; //MISO=input and MOSI,SCK,SS = output
PORTB = 0x40; //MISO上拉电阻有效
SPCR = 0xC5; //SPI允许,从机模式,MSB,允许SPI中断,极性方式01,1/16系统时钟速率
SPSR = 0x00;
temp = SPSR;
temp = SPDR; //清空SPI,和中断标志,使SPI空闲
}
//***************************************************************
//将数据0XFF送给SPDR,等待主机发送,(接收方接收到的第一个数据为0xFF应忽略 )
//***************************************************************
void spi_send(void)
{
fill_tx_buffer(); //调用fill_tx_buffer函数,将要发送的数据加载到发送缓冲区
spi_init(); //初始化spi为从方式
SPDR=0xFF; //开始发送,接收方接收到的第一个数据为0xFF应忽略
sei(); //开总中断
SPCR|=(1<<SPIE)|(1<<SPE); //使能SPI,开SPI中断
SPI_TxHead = 0; //已发送数据计数器清0
}
int main(void)
{
PORTC=0xFF;
DDRC=0xFF; //PC口设为输出高电平,灯灭
SPI_RxHead=0;
SPI_TxHead=0;
Tx_counter=SPI_TX_BUFFER_MASK;
spi_send();
while(1)
{
if(spi_trans_com==1) //如果接收完成标志为1,表明有所数据已接收
{
read_rx_buffer(); //调用read_rx_buffer函数,将接收到的数据从接收缓冲区读出
spi_trans_com=0; //读完清除接收完成标志
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -