STM32-(18):SPI与数码管(SPI)

发布者:advancement4最新更新时间:2019-08-12 来源: eefocus关键字:STM32  SPI  数码管 手机看文章 扫描二维码
随时随地手机看文章

SPI串行接口

SPI是由Motorala公司提出的一种同步串行外围接口。它在速度要求不高、低功耗、需保存少量参数的智能化传感系统中得到了广泛应用。
SPI是一个全双工的同步串行接口。在数据传输过程中,总线上只能是一个主机和一个从机进行通信。

1、MISO(Master In Slave Out)
主机输入、从机输出信号。
2、MOSI(Master Out Slave In)
主机输出、从机输入信号。
3、SCK(Serial Clock)
串行时钟信号。(用来同步使用的)
4、SS(Slave Select)
从机选择信号,低电平有效。

SPI系统连接

SPI总线可在软件的控制下构成各种简单或复杂的系统。
在这里插入图片描述

SPI通信工作原理

SPI的基本结构相当于两个8位移位寄存器的首位相接,构成16位的环形移位寄存器。从而实现了主机与从机的数据交换。
在这里插入图片描述

SPI框图

在这里插入图片描述
分析:
①首先看SCK 管脚,通过波特率发生器产生时钟信号,这个信号可以出去给从机使用,也可以进来给自己驱动 COMMUNICATION CONTROL(通信控制),其中波特率发生器由BR0、BR1、BR2控制,由这三个值来决定波特率的速度,通信控制受MSTR、SSM、SSI控制
,如果通信控制出错,比如控制的CRCERR(CRC校验错误)、MODF(模式)、OVR(数据溢出),就会在SPI_SR的相应位置1。通信控制出来的信号连接着 MASTER CONTROL LOGIC(主控逻辑电路),中控逻辑电路控制着MOSI、MISO这一块。
②数据从MISO进来,进入SHIFT REGISTER(移位寄存器),移位寄存器数据一旦8位接收完整之后,会自动放到 RX BUFFER 中,我们可以通过 RX BUFFER可以读取数据。 当我们要发送内容,就是通过总线(地址总线,数据总线)将数据写入 TX BUFFER 中去,然后送到移位寄存器 ,数据一旦8位接收完整之后,可以通过MOSI将数据发送出去。

SPI通信的几个步骤

1.SPI主从模式

在这里插入图片描述

设置MSTR(主设备选择)和SPE位(使能位)来选择是否工作在主模式还是从模式下。(这两个位都在SPI_CR1寄存器中都可以设置),作为从机,片选要接地,可以硬件实现也可以软件实现,接电源是作主机

2.时钟信号的相位和极性

SPI接口可由CPOL和CPHA设定4种不同传输格式的时序。(CPOL和CPHA在SPI_CR1寄存器中)
CPOL决定时钟脉冲SCK的有效脉冲方式(正脉冲、负脉冲)。CPHA决定数据线MOSI什么时候输出数据或采集数据。
根据CPOL和CPHA的组合数目,一共有4种设置情况。

在这里插入图片描述
分析:
CPOL决定了脉冲的方式,第一行(CPOL=0),是正脉冲,第二行(CPOL=1),是负脉冲(空闲时高电平,来数据下降沿);当CPHA=0,数据是先出来的,即比上方的SCK的电平变化(时钟输出)要快,大概快半拍,我们称之为数据传输相位超前;当CPHA=1,SCK的电平变化之后数据才会出来,相位是同步的,当在SCK的第二个上升沿或者下降沿的时候才开始数据采集

4种时序下的数据传输,其中“第一位数据的输出”和“其他位数据的输出”栏是表示数据在什么时候更新输出。还需注意数据采样是上升沿还是下降沿有效。

数据与时钟的相位关系如下图:
在这里插入图片描述

3.数据帧的格式

根据SPI_CR1寄存器中的LSBFIRST位,输出数据位时可以MSB在先也可以LSB在先。
根据SPI_CR1寄存器的DFF位,每个数据帧可以是8位或是16位。所选择的数据帧格式对发送和/或接收都有效。

SPI主模式通信

在主模式时,串行时钟在SCK脚产生。
配置步骤:

  1. 通过 SPI_CR1寄存器的 BR[2:0]位定义串行时钟波特率

  2. 选择 CPOL和CPHA 位,定义数据传输和串行时钟间的相位关系

  3. 设置 DFF 位来定义8或16位数据帧格式

  4. 配置 SPI_CR1寄存器的 LSBFIRST 位定义帧格式

  5. 如果 NSS 引脚需要工作在输入模式,硬件模式中在整个数据帧传输期间应把 NSS 脚连接到髙电平:在软件模式中,需设置 SPI_CR1寄存器的 SSM 和 SSI 位 。 如 果 NSS 引脚工作在输出模式.则只需设置 SSOE 位

  6. 必须设置 MSTR 和 SPE 位(只当 NSS 脚被连到高电平.这些位才能保持置位)
    在这个配置中, MOSI 脚是数据输出,而 MISO 脚是数据输入。

数据发送过程

1、 当一字节写进发送缓冲器时,发送过程开始。
2、 在发送第一个数据位时,数据字被并行地(通过内部总线–TX BUFFER)传入移位寄存器,而后串行地移出到 MOSI 脚上; MSB 在先还是 LSB 在先,取决于 SPI_CR1寄存器中的 LSBFIRST 位。数据从发送缓冲器传输到移位寄存器 TXE 标志将被置位,如果设置 SPI_CR1寄存器中的 TXEIE 位,将产生中断。
3、 在试图写发送缓冲器之前,需确认 TXE 标志应该是1

数据接收过程

当数据传输完成时:
1、 移位寄存器里的数据传送到接收缓冲器(8位–>RX BUFFER),并且 RXNE 标志被置位(硬件接受满自动置位1)。如果 SPI_CR2寄存器中的 RXEIE 位被设置,则产生中断。
2、 读 SPI_ DR 寄存器时, SPI 设备返回接收到的数据字。读 SPI_DR 寄存器将清除RXNE 位(也是硬件自动清零)。

数码管显示 123.4

main.c

/* Includes ------------------------------------------------------------------*/

#include "stm32f10x_lib.h"   //包含了所有的头文件 它是唯一一个用户需要包括在自己应用中的文件,起到应用和库之间界面的作用。

#include "../Module_Function/Module.h"

#include


TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;

TIM_OCInitTypeDef  TIM_OCInitStructure;

ErrorStatus  HSEStartUpStatus;


void Delay_Ms(u16 time);

void RCC_Configuration(void);

void GPIO_Configuration(void);


/* Private functions ---------------------------------------------------------*/ 

/*******************************************************************************

* Function Name  : main

* Description    : Main program.

* Input          : None

* Output         : None

* Return         : None

*******************************************************************************/

int main(void)

{

// u16 i=0,j;

#ifdef DEBUG

  debug();

#endif


  RCC_Configuration();//使能外设时钟

SEG_Init();


//========实现数码管显示==========

  while (1)

  {

/*for(i=0;i<9999;i++)

{

for(j=0;j<500;j++)

SEG_Display(i,0);

} */   

SEG_Display(1234,3);

  }

}


/*******************************************************************************

* Function Name  : Delay_Ms

* Description    : delay 1 ms.

* Input          : time (ms)

* Output         : None

* Return         : None

*******************************************************************************/

void Delay_Ms(u16 time)  //延时函数

u16 i,j;

for(i=0;i  for(j=1000;j>0;j--);

}


/*******************************************************************************

* Function Name  : RCC_Configuration

* Description    : Configures the different system clocks.

* Input          : None

* Output         : None

* Return         : None

*******************************************************************************/

void RCC_Configuration(void) 

{

//==========================使用外部RC晶振========================================

  RCC_DeInit(); //初始化为缺省状态

  RCC_HSEConfig(RCC_HSE_ON);  //高速时钟使能

  while (RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET);  //等待高速时钟使能就绪


    FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); //Enable Prefetch Buffer 

    FLASH_SetLatency(FLASH_Latency_2);   // Flash 2 wait state 

    RCC_HCLKConfig(RCC_SYSCLK_Div1); // HCLK = SYSCLK 

    RCC_PCLK2Config(RCC_HCLK_Div1); // PCLK2 = HCLK 

    RCC_PCLK1Config(RCC_HCLK_Div2);   // PCLK1 = HCLK/2 

    RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9); // PLLCLK = 8MHz * 9 = 72 MHz  

    RCC_PLLCmd(ENABLE);   // Enable PLL 

    while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET); // Wait till PLL is ready 


    RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);   // Select PLL as system clock source 

    while(RCC_GetSYSCLKSource() != 0x08); // Wait till PLL is used as system clock source 

}



Seg_Module.c

/****************************************************************************

* 版权: 源享教育(www.yxarm.net)

* 文件: Seg_Module.c

* 版本: 1.0

* 说明: MP3播放器当前播放歌曲序号,播放第1首时4位数码管显示0001,依次排列

* 作者: 刘斌

* 时间: 2011.6.21

* 说明: 数码管段显由HC595控制,位显由IO口SEG_A1/SEG_A2/SEG_A3/SEG_A4控制。

* HC595使用SPI通信方式,Cortex M3的SPI使用步骤如下:

* 1、使能APB2外设SPI1时钟:RCC_APB2PeriphClockCmd();

* 2、将外设SPI寄存器重设为缺省值:SPI_I2S_DeInit();

* 3、初始化外设SPI寄存器:SPI_Init();

* 4、使能APB2外设SPI:SPI_Cmd();

* 5、调用SPI数据发送函数:SPI_I2S_SendData();

------------------------------修改记录--------------------------------------

* 修改功能:

* 修改时间:

* 修改作者:

* 遗留问题:

****************************************************************************/

#include "stm32f10x_lib.h"   //包含了所有的头文件 它是唯一一个用户需要包括在自己应用中的文件,起到应用和库之间界面的作用。


#define HC595_nCS GPIO_Pin_0 //HC595_nCS = PA0

#define HC595_RCK GPIO_Pin_1 //HC595_RCK = PA1


#define SEG_A1 GPIO_Pin_8 //SEG_A1 = PC8

#define SEG_A2 GPIO_Pin_15 //SEG_A2 = PB15

#define SEG_A3 GPIO_Pin_9 //SEG_A3 = PC9

#define SEG_A4 GPIO_Pin_8 //SEG_A4 = PE8


u8 const NumberTube_TAB[10]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90};//数码管0~9

/*******************************************************************************

* Function Name  : SEG_Init

* Description    : SEG数码管引脚,SPI1引脚初始化

* Input          : None

* Return         : None

*******************************************************************************/

void SEG_Init(void)

{

GPIO_InitTypeDef GPIO_InitStructure; // 声明一个IO口结构体变量

SPI_InitTypeDef SPI1_InitStructure; //声明一个SPI结构体变量


RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE); // 使能APB2外设GPIOA时钟

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB , ENABLE); // 使能APB2外设GPIOB时钟

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC , ENABLE); // 使能APB2外设GPIOC时钟

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE , ENABLE); // 使能APB2外设GPIOE时钟

RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1 , ENABLE); // 使能APB2外设SPI1时钟

    //==========PA口IO结构体初始化============

  GPIO_InitStructure.GPIO_Pin = HC595_nCS|HC595_RCK; //选择PA.0,PA.1

  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //管脚频率为50MHZ

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //模式为推挽输出

  GPIO_Init(GPIOA, &GPIO_InitStructure);    //初始化GPIOA寄存器

//==========PB口IO结构体初始化============

  GPIO_InitStructure.GPIO_Pin = SEG_A2; //选择PB.15

  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //管脚频率为50MHZ

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //模式为推挽输出

  GPIO_Init(GPIOB, &GPIO_InitStructure);    //初始化GPIOB寄存器

//==========PC口IO结构体初始化============

  GPIO_InitStructure.GPIO_Pin = SEG_A1|SEG_A3; //选择PC.8,PC.9

  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //管脚频率为50MHZ

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //模式为推挽输出

  GPIO_Init(GPIOC, &GPIO_InitStructure);    //初始化GPIOC寄存器

//==========PE口IO结构体初始化============

  GPIO_InitStructure.GPIO_Pin = SEG_A4; //选择PE.8

  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //管脚频率为50MHZ

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //模式为推挽输出

  GPIO_Init(GPIOE, &GPIO_InitStructure);    //初始化GPIOE寄存器


//==========SPI1复用功能初始化============

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7; //选择PA.4,PA.5, PA.6,PA.7

  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //管脚频率为50MHZ

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //模式为复用推挽输出 (SPI1)

  GPIO_Init(GPIOA, &GPIO_InitStructure);    //初始化GPIOA寄存器


//==========设置SPI1工作模式==============

SPI1_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //SPI设置为双线双向全双工

SPI1_InitStructure.SPI_Mode = SPI_Mode_Master; //设置为主SPI

SPI1_InitStructure.SPI_DataSize = SPI_DataSize_8b; //SPI发送接收8位帧结构

SPI1_InitStructure.SPI_CPOL = SPI_CPOL_High; //CPOL = 1

SPI1_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; //CPHA = 0

SPI1_InitStructure.SPI_NSS = SPI_NSS_Hard; //NSS由外部管脚管理

SPI1_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_64;//分频值为64

SPI1_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //数据传输LSB(低位)开始

SPI1_InitStructure.SPI_CRCPolynomial = 7;

SPI_I2S_DeInit(SPI1); //将外设SPI1寄存器重设为缺省值 ;

SPI_Init(SPI1, &SPI1_InitStructure);//初始化外设SPI1寄存器

//==========使能SPI1========================

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

GPIO_ResetBits(GPIOA, HC595_nCS);

}

/*******************************************************************************

[1] [2]
关键字:STM32  SPI  数码管 引用地址:STM32-(18):SPI与数码管(SPI)

上一篇:STM32-(17):SPI与数码管,
下一篇:STM32-(19):I2C通信(理论基础)

推荐阅读最新更新时间:2024-11-11 11:54

STM32之FLASH操作
说到STM32的FLSAH,我们的第一反应是用来装程序的,实际上,STM32的片内FLASH不仅用来装程序,还用来装 芯片 配置、 芯片 ID、自举程序等等。当然, FLASH还可以用来装数据。 自己收集了一些资料,现将这些资料总结了一下,不想看的可以直接调到后面看怎么操作就可以了。 FLASH分类 根据用途,STM32片内的FLASH分成两部分:主存储块、信息块。 主存储块用于存储程序,我们写的程序一般存储在这里。 信息块又分成两部分:系统存储器、选项字节。 系统存储器存储用于存放在系统存储器自举模式下的启动程序(BootLoader),当使用ISP方式加载程序时,就是由这个程序执行。这个区域由芯片厂写入BootLoa
[单片机]
STM32SPI接口
  STM32的SPI接口支持SPI协议和I2S音频协议,默认为SPI,可通过软件切换为I2S。   SPI接口:   MISO 主设备输入/从设备输出   MOSI 主设备输出/从设备输入   SCK 串口时钟   NSS 从设备选择   初始化例程如下: void SPI_Init(void) {   SPI_InitTypeDef SPI_InitStructure;   GPIO_InitTypeDef GPIO_InitStructure;   RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA|RCC_APB2Periph_SPI1, ENABLE );
[单片机]
STM32 USART寄存器方式编程
#include stm32f10x.h #define GPIOA_ODR_A GPIOA_BASE+0X0C #define GPIOA_IDR_A GPIOA_BASE+0X08 #define GPIOB_ODR_A GPIOB_BASE+0X0C #define GPIOB_IDR_A GPIOB_BASE+0X08 #define GPIOC_ODR_A GPIOC_BASE+0X0C #define GPIOC_IDR_A GPIOC_BASE+0X08 #define GPIOD_ODR_A GPIOD_BASE+0X0C #define GPIOD_IDR_A GPIOD_BASE+0X08
[单片机]
51单片机ADC0809数码管显示光照强度的仿真和源码
51单片机ADC0809 数码管 显示光照强度 源码及仿真文件请自行下载 仿真原理图如下 单片机源码如下: #include reg52.h #include intrins.h #include absacc.h #define uchar unsigned char #define uint unsigned int #define COM0808 XBYTE char code dis_code ={0xc0,0xf9,0xa4,0xb0, 0x99,0x92,0x82,0xf8, 0x80,0x90,0xff}; char find_co
[单片机]
51单片机ADC0809<font color='red'>数码管</font>显示光照强度的仿真和源码
STM32系统学习——RCC(使用HSE/HSI配置时钟)
RCC :reset clock control 复位和时钟控制器。主要讲解时钟部分,特别是要着重理解时钟树,理解了时钟树,STM32 的一切时钟的来龙去脉都会了如指掌。 一、RCC主要作用——时钟部分 设置系统时钟SYSCLK、设置AHB分频因子(决定HCLK是多少)、设置APB2分频因子(设定PCLK2等于多少)、设置APB1分频因子(决定PCLK1等于多少);控制AHB/APB2/APB1这3条总线开启,控制每个外设时钟的开启。 对于SYSCLK、HCLK、PCLK2、PCLK1这4个时钟的配置一般是:PCLK2=HCLK=SYSCLK=PLLCLK=72MHz,PCLK1=HCLK/2=36MHz.这个配置是库
[单片机]
<font color='red'>STM32</font>系统学习——RCC(使用HSE/HSI配置时钟)
实现stm32在FSK调制解调器的综合设计
大致要求:设计一个FSK调制解调器,基带信号码速率为2000B/s,载波速率为4khz和8khz,解调信号要能完整还原基带信号。实现方法多种多样,通信领域内调制解调器的设计大多数用的都是硬件电路,鉴于笔者对编程情有独钟(其实笔者还是懂一点电路设计知识的~),所以最终决定用stm32来设计,纯编程实现。看起来高大上,但实际做起来不难,不过有挺多东西要考虑的。 总的设计思路如下: 首先是基带信号的产生,它也是我们要调制和解调的目标。基带信号由一连串随机的码元序列构成,为了模拟随机的码元序列,笔者用定时器设计8位的PN码序列,码元速率为2000B/s。定时器3定时0.5ms,每进入一次中断,变量num加一,设置一次I
[单片机]
实现<font color='red'>stm32</font>在FSK调制解调器的综合设计
STM32系统架构
在小容量、中容量和 大容量产品中,主系统由以下部分构成: ● 四个驱动单元: ─ Cortex-M3内核DCode总线(D-bus),和系统总线(S-bus) ─ 通用DMA1和通用DMA2 ● 四个被动单元 ─ 内部SRAM ─ 内部闪存存储器 ─ FSMC ─ AHB到APB的桥(AHB2APBx),它连接所有的APB设备 这些都是通过一个多级的AHB总线构架相互连接的,如下图所示: 在互联型产品中,主系统由以下部分构成: ● 五个驱动单元: ─ Cortex-M3内核DCode总线(D-bus),和系统总线(S-bus) ─ 通用DMA1和通用DMA2 ─ 以太网DMA ● 三个被动单元 ─ 内部SRAM ─ 内部闪存
[单片机]
<font color='red'>STM32</font>系统架构
STM32(cortex_m3) 的 Bit-Banding 怎样理解
Bit-Banding的意思:对Bit-Band区一个字的操作对应实际存储器中的一位。 在STM32F10xxx的技术参考手册中第2.3.3节,有这样的描述: Cortex-M3存储器映像包括两个位段(bit-band)区。这两个位段区将别名存储器区中的每个字映射到位段存储器区的一个位,在别名存储区写入一个字具有对位段区的目标位执行读-改-写操作的相同效果 。 即M3利用别名区简化了位操作了位段区的位操作(将一般的读-改-写简化为写)。 别名区空间大小是位段区的32倍(因为每1位映射为1字)。 在STM32F10x里存储器映像中包括2个位段区,分别是: SRAM区低1MB 0x2000 0000 - 0x200f ffff
[单片机]
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved