spi从机程序设计_spi从机程序代码详细介绍

嵌入式设计应用

132人已加入

描述

SPI(serial peripheral interface)串行外围设备接口。是一种全双工同步通信总线。本文为大家介绍两种spi从机程序。

STM32F407的SPI主从机通信程序

#include “spi.h”

u8 SPI_Data[3];

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寄存器

SPI_Cmd(SPI1, ENABLE); //使能SPI外设

//SPI1_ReadWriteByte(0xff);//启动传输

}

//SPI1速度设置函数

//SPI速度=fAPB2/分频系数

//@ref SPI_BaudRate_Prescaler:SPI_BaudRatePrescaler_2~SPI_BaudRatePrescaler_256

//fAPB2时钟一般为84Mhz:

void SPI1_SetSpeed(u8 SPI_BaudRatePrescaler)

{

assert_param(IS_SPI_BAUDRATE_PRESCALER(SPI_BaudRatePrescaler));//判断有效性

SPI1-》CR1&=0XFFC7;//位3-5清零,用来设置波特率

SPI1-》CR1|=SPI_BaudRatePrescaler; //设置SPI1速度

SPI_Cmd(SPI1,ENABLE); //使能SPI1

}

//SPI1 读写一个字节

//TxData:要写入的字节

//返回值:读取到的字节

void SPI1_WriteByte(u8 TxData)

{

while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET){}//等待发送区空

SPI_I2S_SendData(SPI1, TxData); //通过外设SPIx发送一个byte 数据

//while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET){} //等待接收完一个byte

//return SPI_I2S_ReceiveData(SPI1); //返回通过SPIx最近接收的数据

}

void SPI2_Init(void)

{

GPIO_InitTypeDef GPIO_InitStructure;

SPI_InitTypeDef SPI_InitStructure;

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);//使能GPIOA时钟

RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE); //使能SPI1时钟

//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);//复位SPI1

RCC_APB2PeriphResetCmd(RCC_APB1Periph_SPI2,DISABLE);//停止复位SPI1

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寄存器

SPI_Cmd(SPI2, ENABLE); //使能SPI外设

}

//SPI1速度设置函数

//SPI速度=fAPB2/分频系数

//@ref SPI_BaudRate_Prescaler:SPI_BaudRatePrescaler_2~SPI_BaudRatePrescaler_256

//fAPB2时钟一般为84Mhz:

void SPI2_SetSpeed(u8 SPI_BaudRatePrescaler)

{

assert_param(IS_SPI_BAUDRATE_PRESCALER(SPI_BaudRatePrescaler));//判断有效性

SPI2-》CR1&=0XFFC7;//位3-5清零,用来设置波特率

SPI2-》CR1|=SPI_BaudRatePrescaler; //设置SPI2速度

SPI_Cmd(SPI2,ENABLE); //使能SPI1

}

//SPI2 读写一个字节

//TxData:要写入的字节

//返回值:读取到的字节

u8 SPI2_ReadByte()

{

//while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET){}//等待发送区空

//SPI_I2S_SendData(SPI2, TxData); //通过外设SPIx发送一个byte 数据

while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET){} //等待接收完一个byte

return SPI_I2S_ReceiveData(SPI2); //返回通过SPIx最近接收的数据

}

void SPI2_WriteByte(u8 TxData)

{

SPI_I2S_SendData(SPI2, TxData); //通过外设SPIx发送一个byte 数据

while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET){}//等待发送区空

}

//外部中断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;

EXTI_ClearITPendingBit(EXTI_Line4); //清除LINE4上的中断标志位

}

//外部中断5服务程序

//外部中断初始化程序

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;

SPI1_WriteByte(0xaa);

SPI_Data[0]=SPI2_ReadByte();

SPI1_WriteByte(0xc3);

SPI_Data[1]=SPI2_ReadByte();

SPI1_WriteByte(0x55);

SPI_Data[2]=SPI2_ReadByte();

if((SPI_Data[0]==0xaa)&&(SPI_Data[1]==0xc3)&&(SPI_Data[2]==0x55))

{

BEEP=~BEEP;

LED0=~LED0;

LED1=~LED1;

delay_ms(500);

}

memset(SPI_Data,0,3);

}

}

}

基于计数器的spi从机程序设计

SPI 即为:serial peripheral interface,串行外围设备接口。是一种全双工同步通信总线。通信是通过数据传输来完成的,SPI是串行通信协议,也就是说,数据时一位一位传输的。也就是时钟线存在的原因,由于时钟线提供的时钟脉冲,数据发送和数据接收都是基于这个时钟脉冲完成数据传输的,数据通过数据输出线输出,数据在时钟上升沿或者下降沿时改变,在紧接着的下降沿或者上升沿被读取,完成一次数据传输,输入原理和输出一样。也就是说数据输入和输出是在同一个时钟完成的,而区别就是在时钟的上升沿输入那么在时钟下降沿就输出,或者相反。为了实现这一点,一下设计就是通过一个计数器,在计数器数到偶数的时候则输出,计数器数到奇数的时候则输入。代码如下:

程序

程序

程序
程序

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
评论(0)
发评论
fang百川 2018-08-13
0 回复 举报
后面的程序呢 收起回复

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分