打印
[AVR单片机]

SPI全双工通信 [分享]

[复制链接]
4709|11
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
传一个程序,SPI全双工通信,在计算机课上学习了全双工通信的原理,又细细的看了DATASHEET,又看了张军编的关于avr书,才搞出来的。主机与从机互相交换一下各自存储的字符串,然后按UP键,从机传给主机一首音乐,按START键,主机开始唱,音乐部分参考了本论坛上的程序。CLOCK时钟线是由主机控制的。有仿真,从仿真中能看到数据流的流向及时间。
请大家多多指教。

部分程序代码
<主机程序>
#include "iom16v.h"
#include "macros.h"
#define uchar unsigned char
#define uint  unsigned int
#define   UP      0XFE
#define   DOWN    0XFD
#define   START   0XFB
#define   UNVALUE  10
#define   SING_UP    252
#define   SING_DOWN  253
#define   END        254
uint  music[100][2];                     
/************初始化**************/

void DeviceInit(void)                  
{
    CLI();                            //关闭中断                                                
SPIMasterInit();                     //SPI初始化
uart0_init();                        //UART初始化
CTC_Init();                          //比较输出初始化
TIMSK |= (1<<OCIE1A); //开启比较匹配中断
MCUCR=0X00;
DDRC=0X00;
PORTC=0XFF;
  SEI();                              //开全局中断
}
/****************MUSIC数据接收*****************/
void  music_receive(void)
{
    uchar i=0,j=0,flag=0,high=0,low=0;        
         while(flag==0)
          {     
            for(i=0;i<2;i++)
                  {   
                  SPI_SENT(UNVALUE); //*******发空数据,用于启动时钟      
            high=SPDR;  //**************接受从机高八位
               NOP();        //********************************等待从机接收完数据,并把待发送数据
               NOP();       //********************************放入SPSR寄存器中   
      
         SPI_SENT(UNVALUE);
      low=SPDR;  //**************接受从机低八位
           NOP();        //********************************等待从机接收完数据,并把待发送数据
            NOP();       //********************************放入SPSR寄存器中   
         
            music[j]=high*256+low;   
     if((high==END)|(low==END))  {flag=1;music[j+1][1]= END; break;}
                 }
      
       j++;
   
         }
   
}

/*****************choose_key*******************/
uchar  choose_key(void)
{
uchar key;
key=PINC;
delay_ms(50);
if(key==PINC)
{
delay_ms(50);
  if(key==PINC)
  {
       return key;
  }
}
}
/*****************选择传输的音乐**************/
void  music_choose(void)
{

  switch(choose_key())
  {
   
  case     UP:   
                 {
            SPI_SENT(SING_UP);
                        music_receive();  break;
                 }
  case   DOWN:  
                 {
          SPI_SENT(SING_DOWN);
                        music_receive();  break;
                 }
  
  case  START:   {
                      music_play(music);break;   
                 }
  default:break;
  }


}
/****************主函数***********************/
void main(void)
{
    uchar  k=0,flag=0,high=0,low=0,slave_data[80];            
uchar   master_data[]="I am the slave cpu and receive the data of the master's cpu!!  SLAVE  SLAVE  SLAVE  SLAVE  SLAVE";
                           //存储的数据用于发送给从机
    DeviceInit();
delay_ms(10);             //***让从机先进入工作状态
   while(1)//************************************循环发送送与接收数据
     {
      
              SPI_SENT(master_data[k]);
     slave_data[k]=SPDR; //**************接受从机的数据
     Uart0Send(slave_data[k]);///*******发送到串口      
     if(slave_data[k]==END)break;   
             k++;         
     }
while(1)
   {
   music_choose();
   }
}

相关帖子

沙发
lovelyegle|  楼主 | 2009-10-17 22:56 | 只看该作者
#include "iom16v.h"
#include "macros.h"
#define uchar unsigned char
#define uint  unsigned int
#define DDR_MISO  6
#define DDR_MOSI  5
#define DDR_SCK   7
#define DDR_SS    4
#define DDR_SPI   DDRB
#define PORT_SPI  PORTB
uchar SPI_RECEIVE(void);
void SPIMasterInit(void);
void SPI_SENT(uchar TranData) ;
/*********** SPI主机初始化***************/
void SPIMasterInit(void)
{
    PORT_SPI |=(1<<DDR_SS);                                              //***使从机SPI不工作
    DDR_SPI |= (1<<DDR_SS);                                              //***输出时钟  
PORTB|=BIT(DDR_SCK)|BIT(DDR_MOSI);                                   //************配合时钟极性(为高)
DDR_SPI |= (1<<DDR_SCK)|(1<<DDR_MOSI);                               //**************配置输出,时钟高
PORTB|=BIT(DDR_MISO);                                                //************接收从机的数据
    DDR_SPI &=~(1<<DDR_MISO);                                            //**************配置输入
    SPCR = (1<<SPE)|(1<<MSTR)|(1<<CPOL)|(1<<CPHA)|(1<<SPR0);             //****SPI使能,主机,空闲时 时钟高,
}                                                                        //时钟频率为FLOC/16

/************SPI数据发送*************/

void SPI_SENT(uchar TranData)
{
  uchar  clear;
  PORTB&=~BIT(PORTB4);   //***使从机SPI  ENABLE
  clear=SPSR;                          //清SPSR
  clear=SPDR;                          //清SPSR
  SPDR = TranData;                    // 启动数据传输
  while (!(SPSR & (1<<SPIF)));        // 等待传输结束
    PORTB|=BIT(PORTB4);   //***使从机SPI  UNENABLE
}     
//************SPI接收函数*****************//
/*uchar SPI_RECEIVE(void)
{
  uchar  clear,data;
while (!(SPSR & (1<<SPIF)));  // 等待传输结束
  clear=SPSR;                   //清SPSR
  data=SPDR;                     //清SPSR
return data;
}*/

从机

/***************************************
SLAVE机先工作,等待主机发送数据,以免主机先工作,
发送数据后,从机丢失一定的时钟信号(这将导致此次通信的全
部数据出错)
***************************************/
#include "iom16v.h"
#include "macros.h"
#define uchar unsigned char
#define uint  unsigned int
#define   END       254
#define   SING_UP    252
#define   SING_DOWN  253
extern flash unsigned int music_data1[][2];
extern flash unsigned int music_data2[][2];
extern flash unsigned int music_data3[][2];
extern flash unsigned int music_data4[][2];
extern flash unsigned int music_data5[][2];
extern flash unsigned int music_data6[][2];
extern flash unsigned int music_data7[][2];
extern flash unsigned int music_data8[][2];
extern flash unsigned int music_data9[][2];
extern flash unsigned int music_data10[][2];
extern flash unsigned int music_data11[][2];
/************初始化****************/
void DeviceInit(void)
{
    CLI();
uart0_init();
SPISlaveInit();
MCUCR = 0;
TIMSK = 0;
GICR  = 0;
SEI();
}
/*************主函数*****************/
void main(void)
{
    uchar i=0,j=0,high=0,low=0,k=0,master_data[80];//*******************存储主机中的数据
    flash uint (*p)[2];//***************p指向程序存储区的数组指针
uchar slave_data[]="I am the master cpu and receive the data of the slave's cpu!! MASTER MASTER MASTER MASTER MASTER";      
p=music_data4;           
    DeviceInit();
   while(slave_data[k]!=0)        //*************保证把从机数据发送完
     {  
        SPI_SENT(slave_data[k]);
              master_data[k]=SPDR;//接收主机传来的数据
     Uart0Send(master_data[k]);//串口显示数据
          k++;
      }
   SPI_SENT(END);
   SPDR=0x00;
while(1)
{   
      
    if(SPI_RECEIVE()==SING_UP)
    {
  while(p[j][i]!=END)
      {  
    for(i=0;i<2;i++)
         {  
               high=p[j][i]/256;//****高八位
      low=p[j][i]%256;//***低八位
               SPI_SENT(high);//****发高八位
         SPI_SENT(low);//****发低八位
   }
           j++;
      }
    SPI_SENT(END);
   SPDR=0X00;
   j=0;
   i=0;
   }

  
}
}

使用特权

评论回复
板凳
lovelyegle|  楼主 | 2009-10-17 22:58 | 只看该作者
#include "iom16v.h"


#include "macros.h"
#define uchar unsigned char
#define uint  unsigned int
#define DDR_MISO  6
#define DDR_MOSI  5
#define DDR_SCK   7
#define DDR_SS    4
#define DDR_SPI   DDRB
void SPISlaveInit(void);
void SPI_SENT(uchar TranData);
uchar SPI_RECEIVE(void);

/****************从机初始化***************/
void SPISlaveInit(void)
{
    DDR_SPI &=~((1<<DDR_SCK)|(1<<DDR_MOSI));
PORTB|=BIT(DDR_SCK)|BIT(DDR_MOSI);     
    DDR_SPI |= (1<<DDR_MISO);            
PORTB|=BIT(DDR_MISO);                                         //***设置为输出
    SPCR = (1<<SPE)|(1<<CPOL)|(1<<CPHA);                          //与主机的设置要一致
DDR_SPI &=~(1<<DDR_SS);
    PORTB|=BIT(DDR_SS);
}                                       
                                         
                                       
//**************发送函数******************/
void SPI_SENT(uchar TranData)
{
   uchar  clear;
   clear=SPSR;
   clear=SPDR;
   SPDR = TranData;                                               // 启动数据传输
  while (!(SPSR & (1<<SPIF)));                                    // 等待传输结束
}     
/**********接收函数***************/
uchar SPI_RECEIVE(void)
{
  uchar  clear,data;
while (!(SPSR & (1<<SPIF)));  // 等待传输结束
clear=SPSR;
data=SPDR;
return data;
}

使用特权

评论回复
地板
lovelyegle|  楼主 | 2009-10-17 23:00 | 只看该作者
仿真

1.png (21.7 KB )

1.png

2.png (29.62 KB )

2.png

使用特权

评论回复
5
Karlshen| | 2009-10-17 23:15 | 只看该作者
绝对的好东西,顶!

使用特权

评论回复
评分
参与人数 1威望 +1 收起 理由
sunwu111 + 1 很给力!
6
lovelyegle|  楼主 | 2009-10-18 19:44 | 只看该作者
希望对大家有用处

使用特权

评论回复
7
Cypress-lh| | 2009-10-18 19:47 | 只看该作者
不错,好东西,收藏了,谢谢LZ

使用特权

评论回复
8
Cypress-lh| | 2009-10-18 19:58 | 只看该作者
好东西,收藏了

使用特权

评论回复
9
wangwo| | 2009-10-20 19:20 | 只看该作者
真不错

使用特权

评论回复
10
lovelyegle|  楼主 | 2009-10-20 21:11 | 只看该作者
感谢支持哈

使用特权

评论回复
11
Karlshen| | 2009-10-22 20:29 | 只看该作者
第二张图片很不清楚

使用特权

评论回复
12
lovelyegle|  楼主 | 2009-10-22 20:32 | 只看该作者
发上来就成这样了:L

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

77

主题

640

帖子

1

粉丝