不同电平类型单片机之间的SPI通信

2020-01-18 18:44发布

本帖最后由 xxguo 于 2012-10-2 20:50 编辑

现有STC12C5616和CC2530两个单片机。需要两个单片机SPI通信(5616为master,2530为slaver),请问现在有哪些需要注意的问题呢?
我已经实现5616和5616之间的SPI以及2530与2530之间的SPI通信。但是交叉之后就是没有反应,不知道可能是哪里的问题呢?
/*******************************************************************************
date   : 2010/08/29
writer :on the way..

Port   :P0_2,P0_3,P0_4,P0_5    这四个端口是用于UART0外设配置
         P1_0,P1_1            这两个端口是LED1和LED2
         P1_4,P1_5,P1_6,P1_7    这四个端口用于SPI通信
fuction:SPI_DMA中断方式通信
         从模式:配置好DMA的参数,使能DMA中断之后,开启DMA,如
      果串口1有接收到数据,这是会触发DMA,传输数据到指定的数组
      rxBufferSlave中,这里是可以将整个字符串直接传送过来的,最
      后在串口调试助手中显示on the way..
        
*******************************************************************************/
/*--------------------------------------------------------------------------------
    Master                 Slave
-------------          -------------
|           |          |           |
|P1_4   SSN |--------->|SSN    P1_4|
|           |          |           |
|P1_5   SCK |--------->|SCK    P1_5|
|           |          |           |
|P1_6   MOSI|--------->|MOSI   P1_6|
|           |          |           |
|P1_7   MISO|<---------|MISO   P1_7|
|           |          |           |
-------------          -------------
--------------------------------------------------------------------------------*/
// Slave Mode

#include <iocc2530.h>
#include "hal_cc8051.h"

#define LED1          P1_0
#define LED2          P1_1

#define LED_OFF 1
#define LED_ON  0

#define SSN       P1_4
#define N         13   // Length byte
char rxBufferSlave[13];//接收到的数据放到这个数组中
BOOL sDataReceived;    //接收数据标志位
/******************************************************************************
* @fn  init_port
*
* @brief
*     Initializes components IO port application example.
*
* Parameters:
*
* @param  void
*
* @return void
*
******************************************************************************/
void init_port(void)
{
   IO_FUNC_PORT_PIN(1, 0, IO_FUNC_GIO);    //将P1_0设置为普通的IO口
   IO_DIR_PORT_PIN(1, 0, IO_OUT);          //设置为输出
   
   IO_FUNC_PORT_PIN(1, 1, IO_FUNC_GIO);    //将P1_1设置为普通的IO口
   IO_DIR_PORT_PIN(1, 1, IO_OUT);          //设置为输出
   
   PERCFG |= 0x02;        // PERCFG.U1CFG = 1
   P1SEL |= 0xF0;         // P1_7, P1_6, P1_5, and P1_4 are peripherals
   
}

void init_Baudrate(void)
{
  // a 32 MHz crystal,
  // max baud rate = 32 MHz / 8 = 4 MHz.  
  U1BAUD = 0x00;   // BAUD_M = 0
  U1GCR |= 0x11;   // BAUD_E = 17
}
/******************************************************************************
* @fn  initUART
*
* @brief
*      Initializes components for the UART application example.
*
* Parameters:
*
* @param  void
*
* @return void
*
******************************************************************************/
void initUART(void)
{
   // Setup for UART0
   IO_PER_LOC_UART0_AT_PORT0_PIN2345();//将端口0的2345设置为外设
                  
   //这里的串口0设置为:波特率57600,没有校验位,8位数据,1位停止位,
   UART_SETUP(0, 57600, HIGH_STOP);    //设置串口
}
/*******************************************************************************
* @fn          main
*
* @brief      
*
* @param       none
*
* @return      none
*******************************************************************************/
void main(void)
{
  uint8 i;
  halMcuInit();     //设置时钟源32MHZ
  init_port();      //初始化端口
  init_Baudrate();  //初始化波特率
  initUART();       //初始化UART
  
  // SPI Slave Mode
  U1CSR &= ~0x80;   
  U1CSR |= 0x20;
  
  // Configure phase, polarity, and bit order
  U1GCR |= 0xC0;   // CPOL = CPHA = 1
  U1GCR &=~0x20;    // ORDER = 1
  
  // 1. Clear interrupt flags
  // For pulsed or edge shaped interrupt sources one should clear the CPU interrupt
  // flag prior to clearing the module interrupt flag
  TCON &= ~0x80;
  
  // 2. Set individual interrupt enable bit in the peripherals SFR, if any
  
  // 3. Set the corresponding individual, interrupt enable bit in the IEN0, IEN1, or
  // IEN2 registers to 1
  URX1IE = 1;
  
  
  // SPI Slave
  //-------------------------------------------------------------------------------
  DMA_DESC  dmaConfigRx;
  
  SET_WORD(dmaConfigRx.SRCADDRH, dmaConfigRx.SRCADDRL, &X_U1DBUF);
  SET_WORD(dmaConfigRx.DESTADDRH, dmaConfigRx.DESTADDRL, rxBufferSlave);
  dmaConfigRx.VLEN      = 0;  // Transfer number of bytes commanded by n, + 1
  SET_WORD(dmaConfigRx.LENH, dmaConfigRx.LENL, N + 1); //LEN = nmax + 1
  dmaConfigRx.WORDSIZE  = 0;  // Each transfer is 8 bits
  dmaConfigRx.TRIG      = 17; // Use URX1 trigger 17
  dmaConfigRx.TMODE     = 0;  // One byte transferred per trigger event 0
  dmaConfigRx.SRCINC    = 1;  // Keep the same source addr. for all transfers 0
  dmaConfigRx.DESTINC   = 0;  // Increase dest. addr. by 1 between transfers 1
  dmaConfigRx.IRQMASK   = 1;  // Allow IRCON.DMAIF to be asserted when the transfer 1
  // count is reached
  dmaConfigRx.M8        = 0;  // Use all 8 bits of first byte in source data to
  // determine the transfer count
  dmaConfigRx.PRIORITY  = 2;  // DMA memory access has high priority
  
  // Save pointer to the DMA config. struct into DMA ch. 0 config. registers
  SET_WORD(DMA0CFGH, DMA0CFGL, &dmaConfigRx);
  //-------------------------------------------------------------------------------
  
  //-------------------------------------------------------------------------------
  // 1. Clear interrupt flags
  // For pulsed or edge shaped interrupt sources one should clear the CPU interrupt
  // flag prior to clearing the module interrupt flag
  DMAIF = 0;          //清除DMA中断标志位
  DMAIRQ &= ~0x01;   
  
  // 2. Set individual interrupt enable bit in the peripherals SFR, if any
  // No flag for the DMA (Set in the DMA struct (IRQMASK = 1))
  
  // 3. Set the corresponding individual, interrupt enable bit in the IEN0, IEN1, o
  // IEN2 registers to 1
  DMAIE = 1;  //使能DMA中断
  
  // 4. Enable global interrupt
  EA = 1;     //使能总中断
  //-------------------------------------------------------------------------------
  
  //-------------------------------------------------------------------------------
  DMAARM = 0x01;   //使得DMA通道0处于准备好的状态,如果有数据接收到,就会执行中断语句
  
  while (1)  
  {
    if (sDataReceived)
    {
      sDataReceived = FALSE; // All 10 bytes are received
      for(i=0;i<sizeof(rxBufferSlave)+1;i++)
      {
        U0DBUF = rxBufferSlave;
        while(UTX0IF == 0);    //等待发送完毕
        UTX0IF = 0;
      }
    }
  }  
}


#pragma vector=DMA_VECTOR
  __interrupt void dma_IRQ(void)
{
    DMAIF = 0;               // Clear the CPU DMA interrupt flag
    DMAIRQ &= ~0x01;       // DMA channel 0 module interrupt flag
    sDataReceived = TRUE;    // All 10 bytes are received
}
//-------------------------------------------------------------------------------
  
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
24条回答
xxguo
1楼-- · 2020-01-18 21:25
本帖最后由 xxguo 于 2012-10-2 20:46 编辑

上面是用别人的2530的程序改的。下面的是5615的程序:
/* SPI主机程序,无中断串口接收并用SPI发送---------------------------------------
*硬件:STC12C5616,晶振12MHZ
*程序名称:main.c
*作者    :UESTC-35
*日期    :7/17/2011
连接方式 :三线连接
        主单片机 I/O 口         I/O 口 从单片机
;
; +--------------+ MISO <-- 位流方向 MISO +--------------+
; | SPI             |<<-----------------|      SPI       |
; |8 位移位寄存器   |                   |8 位移位寄存器  |
; |                 |---------------->> | |              |
; +-------+------+ MOSI 位流方向 --> MOSI +-------^------+
; |                 |                   |                |
; |                 | SCLK         SCLK |                |
; +---------------------------->>------------------------+
--------------------------------------------------------------------*/
#include "reg51.h"
#define SPIF  ( SPSTAT & 0x80 )  //查询SPIF是否置位,SPIF不能进行位操作
/*通信端口设置-------------------------------------------------------*/

/**********************************************************************
定义寄存器
************************************************************************/
sfr       AUXR    =   0x8e;           //Auxiliary register

sfr       SPSTAT  =   0x84;           //SPI status register  1000 0100
//#define   SPIF        0x80            //SPSTAT.7
#define   WCOL        0x40            //SPSTAT.6

sfr       SPCTL   =   0x85;           //SPI control register 1000 0101  master  SPI禁止 MSB先发 主模式  。。。16分频
#define   SSIG        0x80            //SPCTL.7
#define   SPEN        0x40            //SPCTL.6
#define   DORD        0x20            //SPCTL.5
#define   MSTR        0x10            //SPCTL.4
#define   CPOL        0x08            //SPCTL.3
#define   CPHA        0x04            //SPCTL.2
#define   SPDHH       0x00            //CPU_CLK/4
#define   SPDH        0x01            //CPU_CLK/16
#define   SPDL        0x02            //CPU_CLK/64
#define   SPDLL       0x03            //CPU_CLK/128

sfr       SPDAT   =   0x86;           //SPI data register
/////////////////////////////////////////////////////////////////////
sbit SCLK = P1^7;
sbit MISO = P1^6;
sbit MOSI = P1^5;
sbit SS   = P1^4;
unsigned char UART_SendData=0;
unsigned char UART_RecData=0;
unsigned char SPI_RecData=0;
void Init_System();
void Init_UART();
void Init_SPI();
unsigned char SPI_SendByte(unsigned char SPI_SendData);
void UART_SendByte(unsigned char UART_Send);
/*---------------------------------------------------------
*函数名:main
*函数功能:系统初始化
*输入参数:无
*返回参数:无
----------------------------------------------------------*/
void main()
{
        Init_System();
        while(1)           
        {
                /*  查询UART接收信号 ----------------------------------*/
                while(!RI);     //查看串口是否接收到数据
                {
                        RI=0;               //当接收到数据后,清除接收中断标志
                        UART_RecData=SBUF;   //读入数据
                        UART_SendData=SPI_SendByte(UART_RecData);//将收到的数据由SPI发送出去,又接收回来
//                        UART_SendByte(UART_SendData);
                }
        }
}
/*---------------------------------------------------------
*函数名:Init_System
*函数功能:系统初始化
*输入参数:无
*返回参数:无
----------------------------------------------------------*/
void Init_System()
{
        Init_UART();
        Init_SPI();
}
/*---------------------------------------------------------
*函数名:Init_UART
*函数功能:串口初始化,无中断方式
*输入参数:无
*返回参数:无
----------------------------------------------------------*/
void Init_UART()
{
        TMOD=0x20;//设置定时器1为工作方式2
        AUXR|=0x40;//不对定时器1分频,速度是普通单片机的12倍
        TH1=0xd9; //波特率为9600,晶振为12MHz
        TL1=0xd9;
        TR1=1;   //启动T1
        REN=1;   //串行允许位
        //  PCON=0x80;  //PCON寄存器的SMOD位置一,波特率提高一倍
        SM0=0;
        SM1=1;   //串行方式1
        // ES=1;    //中断接收则开串口中断,查询接收则关闭此句
}
/*---------------------------------------------------------
*函数名:Init_SPI
*函数功能:SPI初始化,SPI的工作方式,不使用SPI中断方式
*输入参数:无
*返回参数:无
----------------------------------------------------------*/
void Init_SPI()
{
        SPCTL = 0xfd;//CPU_CLK/16,时钟前沿为下降沿,后沿采样,主模式,最低位在前,SPI使能
        SPSTAT = 0xc0;//SPDAT.7和SPDAT.6写11,可以将中断标志清零。注意是写1才清零
}
/*---------------------------------------------------------
*函数名:SPI_SendByte
*函数功能:SPI发射接收一体程序
*输入参数:SPI_SendData,经主机发给从机的数据
*返回参数:从机发给主机的数据
----------------------------------------------------------*/
unsigned char SPI_SendByte(unsigned char SPI_SendData)
{
        SS=0;
        SPDAT= SPI_SendData; //将串口接收的数据装入SPI数据寄存器
        while(!SPIF);//等待发送完毕               
        SS=1;
        SPSTAT = 0xc0; //清除中断标志,和写冲突标志,注意是对应位写1才能清零
        SPI_RecData = SPDAT;
        return  SPI_RecData;
}
/*---------------------------------------------------------
*函数名:UART_SendByte
*函数功能:串口发送
*输入参数:UART_Send
*返回参数:无
----------------------------------------------------------*/
void UART_SendByte(unsigned char UART_Send)
{
        TI = 0;            //清除发送SBUF空标志
        SBUF =  UART_Send; //写入SBUF
        while (!TI);       //等待发送完毕
        TI = 0;            //清除发送SBUF空标志
}
xxguo
2楼-- · 2020-01-18 22:36
5615的作为master有部分功能是不需要的已经屏蔽。现在我的想法是电脑串口发数据到5615(master)然后5615通过SPI把数据发给CC2530,之后CC2530通过串口把数据发到电脑终端上面。但是现在的现象是,电脑可以吧数据发到5615,然后5615的SCK引脚上有时钟脉冲,MOSI上也有数据,但是后面的单片机就是没有反应。不知道是为什么呢?是不是两个单片机之间的电平类型不一致呢?
xxguo
3楼-- · 2020-01-18 23:22
 精彩回答 2  元偷偷看……
xxguo
4楼-- · 2020-01-19 02:48
5616的数据手册太大貌似上传不了~~~
xxguo
5楼-- · 2020-01-19 06:57
bug不知道怎么搞啊~~求指教~~~
tony90
6楼-- · 2020-01-19 09:47
这两种单片机都没用过,但如果是电平不同的话,应该增加一个电平转换芯片啊。我以前用DSP的时候要控制12864也要加个电平转换芯片。

一周热门 更多>