keil5-4: 基于STM32F302RBT6的数码管+按键控制——SPI方式

这周一直在调STM32F302RBT6( SPI 1 )+5位8段数码管(两片74HC595控制)+5个按键(一片74HC165控制)。

一 程序目的:

在无按键按下时,5个数码管全显(5个8);

当K1按下时,显示5个1;

当K2按下时,显示5个2;

当K3按下时,显示5个3;

当K4按下时,显示5个4;

当K5按下时,显示5个5;

二 其中的重点如下:

1 SPI的配置

2 595的控制时序

3 165的控制时序

三 程序

 1 包含的程序如下,其中的dma.c 可以去掉.  mykey.c是空的

keil5-4: 基于STM32F302RBT6的数码管+按键控制——SPI方式

2 具体内容:

main.c

#include “rs485.h”
#include “myspi.h”

u16  ADC1_ConvertedValue[5];      
u16  ADC2_ConvertedValue[20];
void delay(u32 n);

int main(void)
{ //int i;
 //GPIO_InitTypeDef GPIO_InitStructure1; 
 u16 ReceiveData;
 RCC_ClocksTypeDef ClockInfo;  
  RCC_GetClocksFreq(&ClockInfo);                            // 
 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);  // 
 RS485_Init(9600);                             // 
 RCC_GetClocksFreq(&ClockInfo);
 myspi_init();  //其他都可以不看,这个是重点。具体内容在下面
  MCU_RX_EN;                                     //

//我的SPI采用的是全双工模式,其中NSS采用软件控制方式:即将MCU的内部NSS信号置1,使MCU工作在Master模式;

//因为我要同时控制595和165,如果用硬件控制方式没办法同时满足595和165的控制时序。(也许可以满足,只是我不会配置)

//而芯片的NSS引脚配置为普通的GPIO,这样NSS就可以在我需要的时候为高为低

 while(1)
  { 
    GPIO_ResetBits(GPIOA, GPIO_Pin_4); // 
    delay(1); //执行完这一步,NSS=0 即165 的SH/LD引脚=0,165载入8个并行口的数据到内部的8个触发器
   GPIO_SetBits(GPIOA, GPIO_Pin_4); // SH/LD 置1,8个并行输入被锁住
   while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE) == RESET){}
     SPI_I2S_SendData16(SPI1,0x0000); // MCU发送0000,数码管显示全显;

                                                                 // 同时产生SPICLKA脉冲给到165的2脚SCK

                                                                 // 同时MCU读取595的16输入数据;

                                                                 // 即MCU作为Master,在全双工模式下,写外设的同时也在读外设

                                                                
     //delay(1);  //这句也可以加上
   while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET){} 
     ReceiveData = SPI_I2S_ReceiveData16(SPI1); //将SPI接收到的数据存在变量ReceiveData中
       if (ReceiveData == 0xFBFF)  
     {
      GPIO_ResetBits(GPIOA, GPIO_Pin_4);  //NSS=0,选中595
      while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE) == RESET){}
      SPI_I2S_SendData16(SPI1,0x00F9); //K1按下,显示5个1
        delay(1);
     }
       else if(ReceiveData == 0xFEFF)
     {
      GPIO_ResetBits(GPIOA, GPIO_Pin_4);
      while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE) == RESET){}
      SPI_I2S_SendData16(SPI1,0x00A4); //K2按下,显示5个2
        delay(1);
     }
 else if (ReceiveData == 0xFDFF)
     {
      GPIO_ResetBits(GPIOA, GPIO_Pin_4);
      while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE) == RESET){}
      SPI_I2S_SendData16(SPI1,0x00B0); //K3按下,显示5个3
        delay(1);
     }
 else if(ReceiveData == 0xEFFF)
     {
      GPIO_ResetBits(GPIOA, GPIO_Pin_4);
      while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE) == RESET){}
      SPI_I2S_SendData16(SPI1,0x0099); //K4按下,显示5个4
        delay(1);
     }
 else if(ReceiveData == 0xF7FF)
     {
      GPIO_ResetBits(GPIOA, GPIO_Pin_4);
      while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE) == RESET){}
      SPI_I2S_SendData16(SPI1,0x0092); //K5按下,显示5个5
        delay(1);
     }    
  }
}

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

myspi.c :

#include “myspi.h”
#include “stm32f30x_spi.h”
#include “delay.h”

void delay(u32 n);  //这是一个外部函数

void myspi_init()
{
 GPIO_InitTypeDef GPIO_InitStructure;
 GPIO_InitTypeDef GPIO_InitStructure1;
 SPI_InitTypeDef  SPI_InitStructure;

 RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1,ENABLE); //开 SPI1 的时钟
 RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA,ENABLE); //开GPIOA时钟,因为用到PA4,5,6,7(SPI1)
 //GPIO_PinAFConfig(GPIOA,GPIO_PinSource4|GPIO_PinSource5|GPIO_PinSource6|GPIO_PinSource7,GPIO_AF_5);
 //配置复用功能时,不要像上面这一行这样配置。这样会配置不成功的,但是我还不知道为什么。
 //GPIO_PinAFConfig(GPIOA,GPIO_PinSource4,GPIO_AF_5);  //PA4即NSS脚,因为我把NSS脚当做GPIO来用,故这句不要
 GPIO_PinAFConfig(GPIOA,GPIO_PinSource5,GPIO_AF_5);
 GPIO_PinAFConfig(GPIOA,GPIO_PinSource6,GPIO_AF_5);
 GPIO_PinAFConfig(GPIOA,GPIO_PinSource7,GPIO_AF_5);
 
 GPIO_InitStructure.GPIO_Mode    = GPIO_Mode_AF;
 GPIO_InitStructure.GPIO_OType  = GPIO_OType_PP;
 GPIO_InitStructure.GPIO_Pin        = GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7;
 GPIO_InitStructure.GPIO_PuPd     = GPIO_PuPd_UP;
 GPIO_InitStructure.GPIO_Speed    = GPIO_Speed_50MHz;
 
 GPIO_InitStructure1.GPIO_Mode   = GPIO_Mode_OUT;
 GPIO_InitStructure1.GPIO_OType  = GPIO_OType_PP;
 GPIO_InitStructure1.GPIO_Pin       = GPIO_Pin_4;
 GPIO_InitStructure1.GPIO_PuPd    = GPIO_PuPd_UP;
 GPIO_InitStructure1.GPIO_Speed   = GPIO_Speed_50MHz;
 
 GPIO_Init(GPIOA,&GPIO_InitStructure);
 GPIO_Init(GPIOA,&GPIO_InitStructure1);
 
 SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8;   //SPI 波特率分频系数
 SPI_InitStructure.SPI_CPHA              = SPI_CPHA_1Edge; // 时钟相位=0,

                                                                                                // 即 在SCK的第一个边沿采样数据位,第二个边沿锁存数据
 SPI_InitStructure.SPI_CPOL              = SPI_CPOL_Low;     // 时钟极性=0,即在没有数据传输时,时钟的空闲状态电平为低

                                                                                                // 若CPOL=0,则在没有数据传输时,时钟的空闲状态电平为高
 SPI_InitStructure.SPI_CRCPolynomial     = 7;     //CRC校验,参考手册上说 这个数大于2就行。没详细研究,随便写了个7
 SPI_InitStructure.SPI_DataSize          = SPI_DataSize_16b; //SPI通信传输的数据位数,也可以选择8位

                                                                                                 //因为我这里控制两片级联的595,所以配置为16位
 SPI_InitStructure.SPI_Direction         = SPI_Direction_2Lines_FullDuplex; //SPI采用全双工模式
 SPI_InitStructure.SPI_FirstBit          = SPI_FirstBit_MSB;  //先传输数据的高位
 SPI_InitStructure.SPI_Mode              = SPI_Mode_Master;//MCU工作在Master模式
 SPI_InitStructure.SPI_NSS               = SPI_NSS_Soft;  //NSS采用软件控制方式。这句会使CR1中的bit9  SSM为置1

SPI_I2S_DeInit(SPI1);   //复位SPI1

 SPI1->CR1 |= 0x0100; //SSI=1 。因为对于SPI主机来说,需要SSM 和SSI同时为1

                                   //NSS有内部和外部引脚。这时候外部引脚留作驱动595和165使用, 内部NSS引脚电平通过SSI位来驱动
 SPI_Init(SPI1,&SPI_InitStructure);  //初始化SPI
 SPI_RxFIFOThresholdConfig(SPI1,SPI_RxFIFOThreshold_QF);  //设置接收FIFO门槛

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

 

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

delay.c :

#include “delay.h”
u32 m;

extern void delay(u32 n)  //ê±n ms
{
 m = 70000*n;
  
 while(m)
 {
  m–;
 }
}

delay.h :

#ifndef __DELAY_H
#define __DELAY_H      
#include “stm32f30x.h”  

extern void delay(u32 n);

#endif

 

四 遗留问题:

1 STM32的SPI 是否有最大时钟限制8M/p>

2 为什么像下面这样配置复用功能不成功/p>

GPIO_PinAFConfig(GPIOA,GPIO_PinSource4|GPIO_PinSource5|GPIO_PinSource6|GPIO_PinSource7,GPIO_AF_5);

3 时钟相位还有些不明白

4请再清楚地解释下595 165的功能表

5 为什么按键按下后,接收到的数据低8位是FF/p>

6 “因为对于SPI主机来说,需要SSM 和SSI同时为1”  这句话怎么理解/p>

7 还需再理解一下FIFO/p>

8 画出595 和165的控制时序图

 

 

 

 

 

 

来源:当风走过

声明:本站部分文章及图片转载于互联网,内容版权归原作者所有,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

上一篇 2018年7月11日
下一篇 2018年7月11日

相关推荐