打印

SPI的DMA主从机通信程序

[复制链接]
612|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
丑帅丑帅的|  楼主 | 2018-7-5 16:28 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
昨天白天调试了SPI的主从机通信程序,晚上回家就加班调试了其DMA的程序,实现的功能和昨天发的帖子一样,只是把普通SPI的发送改成了DMA方式发送和接收。具体程序如下:
//LED端口定义
#define LED0 PAout(4)
#define LED1 PAout(5)
#define BEEP PFout(8)
//CS端口定义
#define CS1 PCout(13)
#define CS2 PCout(14)
#define CS3 PBout(12)
#define CS4 PGout(7)
#define buffersize 9
u8 SPI_WriteData[buffersize]={0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99};
u8 SPI_ReadData[buffersize];

void SPI1_Init(void)
{         
  GPIO_InitTypeDef  GPIO_InitStructure;
  SPI_InitTypeDef  SPI_InitStructure;

  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);//使能GPIOB时钟
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);//使能SPI1时钟

  //GPIOFB3,4,5初始化设置
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5;//PB3~5复用功能输出
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;//上拉
  GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化

GPIO_PinAFConfig(GPIOB,GPIO_PinSource3,GPIO_AF_SPI1); //PB3复用为 SPI1
GPIO_PinAFConfig(GPIOB,GPIO_PinSource4,GPIO_AF_SPI1); //PB4复用为 SPI1
GPIO_PinAFConfig(GPIOB,GPIO_PinSource5,GPIO_AF_SPI1); //PB5复用为 SPI1

//这里只针对SPI口初始化
RCC_APB2PeriphResetCmd(RCC_APB2Periph_SPI1,ENABLE);//复位SPI1
RCC_APB2PeriphResetCmd(RCC_APB2Periph_SPI1,DISABLE);//停止复位SPI1

SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;  //设置SPI单向或者双向的数据模式:SPI设置为双线双向全双工
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;                //设置SPI工作模式:设置为主SPI
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;                //设置SPI的数据大小:SPI发送接收8位帧结构
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;                //串行同步时钟的空闲状态为高电平
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;        //串行同步时钟的第二个跳变沿(上升或下降)数据被采样
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;                //NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;                //定义波特率预分频的值:波特率预分频值为256
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;        //指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始
SPI_InitStructure.SPI_CRCPolynomial = 7;        //CRC值计算的多项式
SPI_Init(SPI1, &SPI_InitStructure);       //根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器

  MYDMA_Config1(DMA2_Stream3,DMA_Channel_3,(u32)&SPI1->DR,(u32)SPI_WriteData,buffersize);
SPI_Cmd(SPI1, ENABLE); //使能SPI外设
  SPI_I2S_DMACmd(SPI1,SPI_I2S_DMAReq_Tx,ENABLE);       //开启DMA发送
}
void SPI2_Init(void)
{         
  GPIO_InitTypeDef  GPIO_InitStructure;
  SPI_InitTypeDef  SPI_InitStructure;

  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);//使能GPIOB时钟
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE); //使能SPI2时钟

  //GPIOFB3,4,5初始化设置
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15;//PB3~5复用功能输出
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;//下拉
  GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化

GPIO_PinAFConfig(GPIOB,GPIO_PinSource13,GPIO_AF_SPI2); //PB13复用为 SPI2
GPIO_PinAFConfig(GPIOB,GPIO_PinSource14,GPIO_AF_SPI2); //PB14复用为 SPI2
GPIO_PinAFConfig(GPIOB,GPIO_PinSource15,GPIO_AF_SPI2); //PB15复用为 SPI2

//这里只针对SPI口初始化
RCC_APB2PeriphResetCmd(RCC_APB1Periph_SPI2,ENABLE);//复位SPI2
RCC_APB2PeriphResetCmd(RCC_APB1Periph_SPI2,DISABLE);//停止复位SPI2

SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;  //设置SPI单向或者双向的数据模式:SPI设置为双线双向全双工
SPI_InitStructure.SPI_Mode = SPI_Mode_Slave;                //设置SPI工作模式:设置为主SPI
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;                //设置SPI的数据大小:SPI发送接收8位帧结构
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;                //串行同步时钟的空闲状态为高电平
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;        //串行同步时钟的第二个跳变沿(上升或下降)数据被采样
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;                //NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;                //定义波特率预分频的值:波特率预分频值为256
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;        //指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始
SPI_InitStructure.SPI_CRCPolynomial = 7;        //CRC值计算的多项式
SPI_Init(SPI2, &SPI_InitStructure);  //根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器
  MYDMA_Config2(DMA1_Stream3,0,(u32)&SPI2->DR,(u32)SPI_ReadData,buffersize);//关联相应通道的DMA
SPI_Cmd(SPI2, ENABLE); //使能SPI外设
SPI_I2S_DMACmd(SPI2,SPI_I2S_DMAReq_Rx,ENABLE);       //开启DMA接收
//MYDMA_Enable(DMA1_Stream3,buffersize);
}   
//DMAx的各通道配置
//这里的传输形式是固定的,这点要根据不同的情况来修改
//从存储器->外设模式/8位数据宽度/存储器增量模式
//DMA_StreamxMA数据流,DMA1_Stream0~7/DMA2_Stream0~7
//chxMA通道选择,@ref DMA_channel DMA_Channel_0~DMA_Channel_7
//par:外设地址
//mar:存储器地址
//ndtr:数据传输量  
void MYDMA_Config1(DMA_Stream_TypeDef *DMA_Streamx,u32 chx,u32 par,u32 mar,u16 ndtr)
{

DMA_InitTypeDef  DMA_InitStructure;

if((u32)DMA_Streamx>(u32)DMA2)//得到当前stream是属于DMA2还是DMA1
{
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2,ENABLE);//DMA2时钟使能

}else
{
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1,ENABLE);//DMA1时钟使能
}
  DMA_DeInit(DMA_Streamx);

while (DMA_GetCmdStatus(DMA_Streamx) != DISABLE){}//等待DMA可配置

  /* 配置 DMA Stream */
  DMA_InitStructure.DMA_Channel = chx;  //通道选择
  DMA_InitStructure.DMA_PeripheralBaseAddr = par;//DMA外设地址
  DMA_InitStructure.DMA_Memory0BaseAddr = mar;//DMA 存储器0地址
  DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;//存储器到外设模式
  DMA_InitStructure.DMA_BufferSize = ndtr;//数据传输量
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设非增量模式
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//存储器增量模式
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//外设数据长度:8位
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;//存储器数据长度:8位
  DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;// 使用普通模式
  DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;//中等优先级
  DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;         
  DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
  DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;//存储器突发单次传输
  DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;//外设突发单次传输
  DMA_Init(DMA_Streamx, &DMA_InitStructure);//初始化DMA Stream
}
void MYDMA_Config2(DMA_Stream_TypeDef *DMA_Streamx,u32 chx,u32 par,u32 mar,u16 ndtr)
{

DMA_InitTypeDef  DMA_InitStructure;

if((u32)DMA_Streamx>(u32)DMA2)//得到当前stream是属于DMA2还是DMA1
{
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2,ENABLE);//DMA2时钟使能

}else
{
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1,ENABLE);//DMA1时钟使能
}
  DMA_DeInit(DMA_Streamx);

while (DMA_GetCmdStatus(DMA_Streamx) != DISABLE){}//等待DMA可配置

  /* 配置 DMA Stream */
  DMA_InitStructure.DMA_Channel = chx;  //通道选择
  DMA_InitStructure.DMA_PeripheralBaseAddr = par;//DMA外设地址
  DMA_InitStructure.DMA_Memory0BaseAddr = mar;//DMA 存储器0地址
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;//外设模式到存储器
  DMA_InitStructure.DMA_BufferSize = ndtr;//数据传输量
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设非增量模式
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//存储器增量模式
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//外设数据长度:8位
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;//存储器数据长度:8位
  DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;// 使用普通模式
  DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;//中等优先级
  DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;         
  DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
  DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;//存储器突发单次传输
  DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;//外设突发单次传输
  DMA_Init(DMA_Streamx, &DMA_InitStructure);//初始化DMA Stream
}
//开启一次DMA传输
//DMA_StreamxMA数据流,DMA1_Stream0~7/DMA2_Stream0~7
//ndtr:数据传输量  
void MYDMA_Enable(DMA_Stream_TypeDef *DMA_Streamx,u16 ndtr)
{

DMA_Cmd(DMA_Streamx, DISABLE);                      //关闭DMA传输

while (DMA_GetCmdStatus(DMA_Streamx) != DISABLE){}        //确保DMA可以被设置  

DMA_SetCurrDataCounter(DMA_Streamx,ndtr);          //数据传输量  

DMA_Cmd(DMA_Streamx, ENABLE);                      //开启DMA传输
}   
//外部中断3服务程序
void EXTI3_IRQHandler(void)
{
  Flage=Flage|0x02;
  CS2=0;
  EXTI_ClearITPendingBit(EXTI_Line3);  //清除LINE3上的中断标志位                                                                                   
}
//外部中断4服务程序
void EXTI4_IRQHandler(void)
{         
  Flage=Flage|0x04;
  CS3=0;
  MYDMA_Enable(DMA1_Stream3,buffersize);
  MYDMA_Enable(DMA2_Stream3,buffersize);
  EXTI_ClearITPendingBit(EXTI_Line4);                  //清除LINE4上的中断标志位                                                                                           
}
//外部中断初始化程序
void EXTIX_Init()
{
NVIC_InitTypeDef   NVIC_InitStructure;
EXTI_InitTypeDef   EXTI_InitStructure;
GPIO_InitTypeDef  GPIO_InitStructure;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);//使能SYSCFG时钟
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE); //使能GPIOE时钟

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;//普通输入模式
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100M
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;//上拉
    GPIO_Init(GPIOE, &GPIO_InitStructure);//初始化GPIOE2,3,4,5

SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE, EXTI_PinSource2);//PE2 连接到中断线2
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE, EXTI_PinSource3);//PE3 连接到中断线3
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE, EXTI_PinSource4);//PE4 连接到中断线4
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE, EXTI_PinSource5);//PE5 连接到中断线5

/* 配置EXTI_Line2,3,4 */
EXTI_InitStructure.EXTI_Line = EXTI_Line2 | EXTI_Line3 | EXTI_Line4 | EXTI_Line5;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//中断事件
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; //下降沿触发
EXTI_InitStructure.EXTI_LineCmd = ENABLE;//中断线使能
EXTI_Init(&EXTI_InitStructure);//配置

NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQn;//外部中断2
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x03;//抢占优先级3
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;//子优先级2
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能外部中断通道
NVIC_Init(&NVIC_InitStructure);//配置

NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQn;//外部中断3
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;//抢占优先级2
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;//子优先级2
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能外部中断通道
NVIC_Init(&NVIC_InitStructure);//配置

NVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQn;//外部中断4
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01;//抢占优先级1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;//子优先级2
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能外部中断通道
NVIC_Init(&NVIC_InitStructure);//配置

NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn;//外部中断4
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01;//抢占优先级1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;//子优先级2
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能外部中断通道
NVIC_Init(&NVIC_InitStructure);//配置
}

int main(void)
{

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
delay_init(100);     //初始化延时函数
LED_Init();                                        //初始化LED
  CS_Init();
  SPI1_Init();
  SPI2_Init();
EXTIX_Init();
while(1)
{          
CS2=1;
if(Flage&0x02)
{
Flage=Flage&0xfd;
CS3=1;
}
if(Flage&0x04)
{
Flage=Flage&0xfb;
while(1)
{
if(DMA_GetFlagStatus(DMA2_Stream3,DMA_FLAG_TCIF3)!=RESET)//等待DMA2_Steam3传输完成
{
DMA_ClearFlag(DMA2_Stream3,DMA_FLAG_TCIF3);//清除DMA2_Steam7传输完成标志
break;
    }
}
while(1)
{
if(DMA_GetFlagStatus(DMA1_Stream3,DMA_FLAG_TCIF3)!=RESET)//等待DMA1_Steam3传输完成
{
DMA_ClearFlag(DMA1_Stream3,DMA_FLAG_TCIF3);//清除DMA1_Steam7传输完成标志
break;
    }
}
BEEP=~BEEP;
LED0=~LED0;
LED1=~LED1;
delay_ms(500);
}
}      
}

使用特权

评论回复

相关帖子

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

本版积分规则

741

主题

742

帖子

0

粉丝