• 方案介紹
    • 前言
    • 一 材料準(zhǔn)備
    • 二 引腳使用
    • 三 代碼編寫
    • 四 程序說明
    • 五 參考
  • 附件下載
  • 相關(guān)推薦
申請入駐 產(chǎn)業(yè)圖譜

【做著玩系列-開源】 STM32版電子沙漏(定時(shí)模式+循環(huán)模式)

02/05 09:03
1795
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點(diǎn)資訊討論

聯(lián)系方式.docx

共1個(gè)文件

前言

最近看到一款電子沙漏,感覺還挺好玩的,然后正好要準(zhǔn)備過年了,閑工夫比較多,那咱也來湊湊熱鬧,不過看了開源廣場,有個(gè)STM32版本的,但是不是STM32F103版本的,所以我在他的查考了他的代碼后自己改寫。

關(guān)注微信公眾號(hào)--星之援工作室 發(fā)送關(guān)鍵字(電子沙漏)

代碼含重要注釋,開源,可自行移植

演示視頻


stm32版本 電子沙漏

一 材料準(zhǔn)備

1.開發(fā)板

STM32F103系列開發(fā)板 X 1 :做本次設(shè)備的主控芯片

2.MPU-6050模塊

MPU6050 X 1:反饋方位

3.MAX7219點(diǎn)陣模塊

MAX7219點(diǎn)陣模塊 X 2:實(shí)現(xiàn)沙漏效果

4.按鍵模塊

按鍵 X 3:實(shí)現(xiàn)按鍵功能

二 引腳使用

1.MPU-6050模塊與按鍵模塊

MPU-6050模塊 按鍵模塊
VCC 3.3 GND GND
GND GND IN1 PB12
SCL PB8 IN2 PB13
SDA PB9 IN3 PB14

?2.MAX7219與蜂鳴器

MAX7219-1 MAX7219-2
VCC 5 VCC 5
GND GND GND GND
DIN PA5 DIN PB5
CS PA4 CS PB4
CLK PA6 CLK PB6
蜂鳴器
OUT PB7 GND GND

三 代碼編寫

1.MPU6050部分

這邊部分 我們主要用到了一個(gè)模擬的IIC通信,并且MPU6050的其他配置函數(shù),都是由現(xiàn)成的,我們只要會(huì)讀代碼就好

?IIC.c

#include "IIC.h"
#include "delay.h"
#include "stdio.h"

/**************************實(shí)現(xiàn)函數(shù)********************************************
*函數(shù)原型:		void IIC_Init(void)
*功  能:		初始化I2C對應(yīng)的接口引腳。
*******************************************************************************/
void IIC_Init(void)
{		
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(SCLK_GPIO_CLK | DATA_GPIO_CLK, ENABLE);

	GPIO_InitStructure.GPIO_Pin = SCLK_GPIO_PIN | DATA_GPIO_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 推挽輸出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(SCLK_GPIO_PORT, &GPIO_InitStructure);

	IIC_SCL_1;
	IIC_SDA_1;	
}
// 配置雙向I/O端口為輸出態(tài)
static void SDA_OUT()
{
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(DATA_GPIO_CLK, ENABLE);

	GPIO_InitStructure.GPIO_Pin = DATA_GPIO_PIN; // PC.10  DATA
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_Init(SCLK_GPIO_PORT, &GPIO_InitStructure); // 初始化GPIOC.10
}
// 配置雙向I/O端口為輸入態(tài)
static void SDA_IN()
{
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(DATA_GPIO_CLK, ENABLE);
	GPIO_InitStructure.GPIO_Pin = DATA_GPIO_PIN; // PC.10 DATA
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_Init(DATA_GPIO_PORT, &GPIO_InitStructure); // 初始化GPIOC.10
}
/**************************實(shí)現(xiàn)函數(shù)********************************************
*函數(shù)原型:		void IIC_Start(void)
*功  能:		產(chǎn)生IIC起始信號(hào)
*******************************************************************************/
void IIC_Start(void)
{
	SDA_OUT();     //sda線輸出 
	IIC_SDA_1;	  	  
	IIC_SCL_1;
	delay_us(4);
 	IIC_SDA_0;//START:when CLK is high,DATA change form high to low 
	delay_us(4);
	IIC_SCL_0;//鉗住I2C總線,準(zhǔn)備發(fā)送或接收數(shù)據(jù) 
}

/**************************實(shí)現(xiàn)函數(shù)********************************************
*函數(shù)原型:		void IIC_Stop(void)
*功  能:	    //產(chǎn)生IIC停止信號(hào)
*******************************************************************************/	  
void IIC_Stop(void)
{
	SDA_OUT();//sda線輸出
	IIC_SCL_0;
	IIC_SDA_0;//STOP:when CLK is high DATA change form low to high
 	delay_us(4);
	IIC_SCL_1; 
	IIC_SDA_1;//發(fā)送I2C總線結(jié)束信號(hào)
	delay_us(4);							   	
}

/**************************實(shí)現(xiàn)函數(shù)********************************************
*函數(shù)原型:		uint8_t IIC_Wait_Ack(void)
*功  能:	    等待應(yīng)答信號(hào)到來 
//返回值:1,接收應(yīng)答失敗
//        0,接收應(yīng)答成功
*******************************************************************************/
uint8_t IIC_Wait_Ack(void)
{
	uint8_t ucErrTime=0;
	SDA_IN();      //SDA設(shè)置為輸入  
	IIC_SDA_1;delay_us(1);	   
	IIC_SCL_1;delay_us(1);	 
	while(READ_SDA)
	{
		ucErrTime++;
		if(ucErrTime>50)
		{
			IIC_Stop();
			return 1;
		}
	  delay_us(1);
	}
	IIC_SCL_0;//時(shí)鐘輸出0 	   
	return 0;  
} 

/**************************實(shí)現(xiàn)函數(shù)********************************************
*函數(shù)原型:		void IIC_Ack(void)
*功  能:	    產(chǎn)生ACK應(yīng)答
*******************************************************************************/
void IIC_Ack(void)
{
	IIC_SCL_0;
	SDA_OUT();
	IIC_SDA_0;
	delay_us(1);
	IIC_SCL_1;
	delay_us(1);
	IIC_SCL_0;
}
	
/**************************實(shí)現(xiàn)函數(shù)********************************************
*函數(shù)原型:		void IIC_NAck(void)
*功  能:	    產(chǎn)生NACK應(yīng)答
*******************************************************************************/	    
void IIC_NAck(void)
{
	IIC_SCL_0;
	SDA_OUT();
	IIC_SDA_1;
	delay_us(1);
	IIC_SCL_1;
	delay_us(1);
	IIC_SCL_0;
}					 				     

/**************************實(shí)現(xiàn)函數(shù)********************************************
*函數(shù)原型:		void IIC_Send_Byte(uint8_t txd)
*功  能:	    IIC發(fā)送一個(gè)字節(jié)
*******************************************************************************/		  
void IIC_Send_Byte(uint8_t txd)
{                        
    uint8_t t;   
	SDA_OUT(); 	    
    IIC_SCL_0;//拉低時(shí)鐘開始數(shù)據(jù)傳輸
    for(t=0;t<8;t++)
    {              
        if( (txd&0x80)>>7 )
				{
					IIC_SDA_1;
				}
				else
				{
					IIC_SDA_0;
				}
					
				
    txd<<=1; 	  
		delay_us(1);   
		IIC_SCL_1;
		delay_us(1); 
		IIC_SCL_0;	
		delay_us(1);
    }	 
} 	 
   
/**************************實(shí)現(xiàn)函數(shù)********************************************
*函數(shù)原型:		uint8_t IIC_Read_Byte(unsigned char ack)
*功  能:	    //讀1個(gè)字節(jié),ack=1時(shí),發(fā)送ACK,ack=0,發(fā)送nACK 
*******************************************************************************/  
uint8_t IIC_Read_Byte(unsigned char ack)
{
	unsigned char i,receive=0;
	SDA_IN();//SDA設(shè)置為輸入
	for(i=0;i<8;i++ )
	{
			IIC_SCL_0; 
			delay_us(1);
			IIC_SCL_1;
			receive<<=1;
			if(READ_SDA)receive++;   
	delay_us(1); 
	}					 
	if (ack){
		IIC_Ack(); //發(fā)送ACK  
	}
	else{
		IIC_NAck();//發(fā)送nACK  
	}
			
	return receive;
}

/**************************實(shí)現(xiàn)函數(shù)********************************************
*函數(shù)原型:		unsigned char I2C_ReadOneByte(unsigned char I2C_Addr,unsigned char addr)
*功  能:	    讀取指定設(shè)備 指定寄存器的一個(gè)值
輸入	I2C_Addr  目標(biāo)設(shè)備地址
		addr	   寄存器地址
返回   讀出來的值
*******************************************************************************/ 
unsigned char I2C_ReadOneByte(unsigned char I2C_Addr,unsigned char addr)
{
	unsigned char res=0;
	
	IIC_Start();	

	IIC_Send_Byte(I2C_Addr);	   //發(fā)送寫命令
	res++;
	IIC_Wait_Ack();
	IIC_Send_Byte(addr); res++;  //發(fā)送地址
	IIC_Wait_Ack();	  
	//IIC_Stop();//產(chǎn)生一個(gè)停止條件	
	IIC_Start();
	IIC_Send_Byte(I2C_Addr+1); res++;          //進(jìn)入接收模式			   
	IIC_Wait_Ack();
	res=IIC_Read_Byte(0);	   
    IIC_Stop();//產(chǎn)生一個(gè)停止條件

	return res;
}


/**************************實(shí)現(xiàn)函數(shù)********************************************
*函數(shù)原型:		uint8_t IICreadBytes(uint8_t dev, uint8_t reg, uint8_t length, uint8_t *data)
*功  能:	    讀取指定設(shè)備 指定寄存器的 length個(gè)值
輸入	dev  目標(biāo)設(shè)備地址
		reg	  寄存器地址
		length 要讀的字節(jié)數(shù)
		*data  讀出的數(shù)據(jù)將要存放的指針
返回   讀出來的字節(jié)數(shù)量
*******************************************************************************/ 
uint8_t IICreadBytes(uint8_t dev, uint8_t reg, uint8_t length, uint8_t *data){
  uint8_t count = 0;
	uint8_t temp;
	IIC_Start();
	IIC_Send_Byte(dev);	   //發(fā)送寫命令
	IIC_Wait_Ack();
	IIC_Send_Byte(reg);   //發(fā)送地址
    IIC_Wait_Ack();	  
	IIC_Start();
	IIC_Send_Byte(dev+1);  //進(jìn)入接收模式	
	IIC_Wait_Ack();
	
   for(count=0;count<length;count++){
		 
		 if(count!=(length-1)){
				temp = IIC_Read_Byte(1);  //帶ACK的讀數(shù)據(jù)
			}
		 	else{
				temp = IIC_Read_Byte(0);	 //最后一個(gè)字節(jié)NACK
			}  


		data[count] = temp;
	}
    IIC_Stop();//產(chǎn)生一個(gè)停止條件
    return count;
}

/**************************實(shí)現(xiàn)函數(shù)********************************************
*函數(shù)原型:		uint8_t IICwriteBytes(uint8_t dev, uint8_t reg, uint8_t length, uint8_t* data)
*功  能:	    將多個(gè)字節(jié)寫入指定設(shè)備 指定寄存器
輸入	dev  目標(biāo)設(shè)備地址
		reg	  寄存器地址
		length 要寫的字節(jié)數(shù)
		*data  將要寫的數(shù)據(jù)的首地址
返回   返回是否成功
*******************************************************************************/ 
uint8_t IICwriteBytes(uint8_t dev, uint8_t reg, uint8_t length, uint8_t* data){
  
 	uint8_t count = 0;
	IIC_Start();
	IIC_Send_Byte(dev);	   //發(fā)送寫命令
	IIC_Wait_Ack();
	IIC_Send_Byte(reg);   //發(fā)送地址
    IIC_Wait_Ack();	  
	for(count=0;count<length;count++){
		IIC_Send_Byte(data[count]); 
		IIC_Wait_Ack(); 
	 }
	IIC_Stop();//產(chǎn)生一個(gè)停止條件

    return 1; //status == 0;
}

/**************************實(shí)現(xiàn)函數(shù)********************************************
*函數(shù)原型:		uint8_t IICreadByte(uint8_t dev, uint8_t reg, uint8_t *data)
*功  能:	    讀取指定設(shè)備 指定寄存器的一個(gè)值
輸入	dev  目標(biāo)設(shè)備地址
		reg	   寄存器地址
		*data  讀出的數(shù)據(jù)將要存放的地址
返回   1
*******************************************************************************/ 
uint8_t IICreadByte(uint8_t dev, uint8_t reg, uint8_t *data){
	*data=I2C_ReadOneByte(dev, reg);
    return 1;
}

/**************************實(shí)現(xiàn)函數(shù)********************************************
*函數(shù)原型:		unsigned char IICwriteByte(unsigned char dev, unsigned char reg, unsigned char data)
*功  能:	    寫入指定設(shè)備 指定寄存器一個(gè)字節(jié)
輸入	dev  目標(biāo)設(shè)備地址
		reg	   寄存器地址
		data  將要寫入的字節(jié)
返回   1
*******************************************************************************/ 
unsigned char IICwriteByte(unsigned char dev, unsigned char reg, unsigned char data){
    return IICwriteBytes(dev, reg, 1, &data);
}

/**************************實(shí)現(xiàn)函數(shù)********************************************
*函數(shù)原型:		uint8_t IICwriteBits(uint8_t dev,uint8_t reg,uint8_t bitStart,uint8_t length,uint8_t data)
*功  能:	    讀 修改 寫 指定設(shè)備 指定寄存器一個(gè)字節(jié) 中的多個(gè)位
輸入	dev  目標(biāo)設(shè)備地址
		reg	   寄存器地址
		bitStart  目標(biāo)字節(jié)的起始位
		length   位長度
		data    存放改變目標(biāo)字節(jié)位的值
返回   成功 為1 
 		失敗為0
*******************************************************************************/ 
uint8_t IICwriteBits(uint8_t dev,uint8_t reg,uint8_t bitStart,uint8_t length,uint8_t data)
{

    uint8_t b;
    if (IICreadByte(dev, reg, &b) != 0) {
        uint8_t mask = (0xFF << (bitStart + 1)) | 0xFF >> ((8 - bitStart) + length - 1);
        data <<= (8 - length);
        data >>= (7 - bitStart);
        b &= mask;
        b |= data;
        return IICwriteByte(dev, reg, b);
    } else {
        return 0;
    }
}

/**************************實(shí)現(xiàn)函數(shù)********************************************
*函數(shù)原型:		uint8_t IICwriteBit(uint8_t dev, uint8_t reg, uint8_t bitNum, uint8_t data)
*功  能:	    讀 修改 寫 指定設(shè)備 指定寄存器一個(gè)字節(jié) 中的1個(gè)位
輸入	dev  目標(biāo)設(shè)備地址
		reg	   寄存器地址
		bitNum  要修改目標(biāo)字節(jié)的bitNum位
		data  為0 時(shí),目標(biāo)位將被清0 否則將被置位
返回   成功 為1 
 		   失敗為0
*******************************************************************************/ 
uint8_t IICwriteBit(uint8_t dev, uint8_t reg, uint8_t bitNum, uint8_t data){
    uint8_t b;
    
    IICreadByte(dev, reg, &b);
    b = (data != 0) ? (b | (1 << bitNum)) : (b & ~(1 << bitNum));
    
    return IICwriteByte(dev, reg, b);
}

//------------------End of File----------------------------

?IIC.h

可以自己修改這里面的配置部分,都是可以自定義的

#ifndef __IIC_H
#define __IIC_H

#include "stm32f10x.h"

#define SCLK_GPIO_PORT GPIOB               /* GPIO端口 */
#define SCLK_GPIO_CLK RCC_APB2Periph_GPIOB /* GPIO端口時(shí)鐘 */
#define SCLK_GPIO_PIN GPIO_Pin_8           /* 連接到SCL時(shí)鐘線的GPIO */

#define DATA_GPIO_PORT GPIOB               /* GPIO端口 */
#define DATA_GPIO_CLK RCC_APB2Periph_GPIOB /* GPIO端口時(shí)鐘 */
#define DATA_GPIO_PIN GPIO_Pin_9           /* 連接到SCL時(shí)鐘線的GPIO */

驅(qū)動(dòng)接口,GPIO模擬IIC
// SCL-->PB9
// SDA-->PB8
// #define SDA_IN()  {GPIOB->MODER&=~(3<<(9*2));GPIOB->MODER|=0<<9*2;}
// #define SDA_OUT() {GPIOB->MODER&=~(3<<(9*2));GPIOB->MODER|=1<<9*2;}

// IO操作函數(shù)
#define IIC_SCL_0 digitalLo(SCLK_GPIO_PORT, SCLK_GPIO_PIN) // digitalLo
#define IIC_SCL_1 digitalHi(SCLK_GPIO_PORT, SCLK_GPIO_PIN) // digitalHi
#define IIC_SDA_0 digitalLo(DATA_GPIO_PORT, DATA_GPIO_PIN)
#define IIC_SDA_1 digitalHi(DATA_GPIO_PORT, DATA_GPIO_PIN)
#define READ_SDA GPIO_ReadInputDataBit(DATA_GPIO_PORT, DATA_GPIO_PIN)

// IIC所有操作函數(shù)
void IIC_Init(void);                      // 初始化IIC的IO口
void IIC_Start(void);                     // 發(fā)送IIC開始信號(hào)
void IIC_Stop(void);                      // 發(fā)送IIC停止信號(hào)
void IIC_Send_Byte(uint8_t txd);          // IIC發(fā)送一個(gè)字節(jié)
uint8_t IIC_Read_Byte(unsigned char ack); // IIC讀取一個(gè)字節(jié)
uint8_t IIC_Wait_Ack(void);               // IIC等待ACK信號(hào)
void IIC_Ack(void);                       // IIC發(fā)送ACK信號(hào)
void IIC_NAck(void);                      // IIC不發(fā)送ACK信號(hào)

void IIC_Write_One_Byte(uint8_t daddr, uint8_t addr, uint8_t data);
uint8_t IIC_Read_One_Byte(uint8_t daddr, uint8_t addr);
unsigned char I2C_Readkey(unsigned char I2C_Addr);

unsigned char I2C_ReadOneByte(unsigned char I2C_Addr, unsigned char addr);
unsigned char IICwriteByte(unsigned char dev, unsigned char reg, unsigned char data);
uint8_t IICwriteBytes(uint8_t dev, uint8_t reg, uint8_t length, uint8_t *data);
uint8_t IICwriteBits(uint8_t dev, uint8_t reg, uint8_t bitStart, uint8_t length, uint8_t data);
uint8_t IICwriteBit(uint8_t dev, uint8_t reg, uint8_t bitNum, uint8_t data);
uint8_t IICreadBytes(uint8_t dev, uint8_t reg, uint8_t length, uint8_t *data);

#endif

//------------------End of File----------------------------

2.max7219部分

這部分主要用到了一個(gè)模擬 SPI 通信 ,這里我們直接用來兩個(gè)模擬的SPI來獨(dú)立控制設(shè)備,更加方便和精確

max7219.c

#include "stm32f10x.h"
#include "max719.h"
#include "delay.h"

uint8_t m_Intensity = 1; // LED亮度

// SPI1 讀寫一個(gè)字節(jié)
void SPI1_ReadWriteByte(uint8_t address, uint8_t data)
{
   uint8_t i;
    // 發(fā)送地址字節(jié)
    for (i = 0; i < 8; i++) {
        // 設(shè)置DIN引腳數(shù)據(jù)位-寫入數(shù)據(jù)
        if (address & 0x80) {
            GPIO_SetBits(MAX7219_DIN_PORT, MAX7219_DIN_PIN);
        } else {
            GPIO_ResetBits(MAX7219_DIN_PORT, MAX7219_DIN_PIN);
        }
        // 產(chǎn)生時(shí)鐘脈沖 1-0
        GPIO_SetBits(MAX7219_CLK_PORT, MAX7219_CLK_PIN);
        delay_us(1); // 延遲1微秒
        GPIO_ResetBits(MAX7219_CLK_PORT, MAX7219_CLK_PIN);
        delay_us(1); // 延遲1微秒
        address <<= 1;
    }

    // 發(fā)送數(shù)據(jù)字節(jié)
    for (i = 0; i < 8; i++) {
        // 設(shè)置DIN引腳數(shù)據(jù)位
        if (data & 0x80) {
            GPIO_SetBits(MAX7219_DIN_PORT, MAX7219_DIN_PIN);
        } else {
            GPIO_ResetBits(MAX7219_DIN_PORT, MAX7219_DIN_PIN);
        }
        // 產(chǎn)生時(shí)鐘脈沖 1-0
        GPIO_SetBits(MAX7219_CLK_PORT, MAX7219_CLK_PIN);
        delay_us(1); // 延遲1微秒
        GPIO_ResetBits(MAX7219_CLK_PORT, MAX7219_CLK_PIN);
        delay_us(1); // 延遲1微秒
        data <<= 1;
    }
}
// SPI1 讀寫一個(gè)字節(jié)
void SPI2_ReadWriteByte(uint8_t address, uint8_t data)
{
   uint8_t i;

    // 發(fā)送地址字節(jié)
    for (i = 0; i < 8; i++) {
        // 設(shè)置DIN引腳數(shù)據(jù)位-寫入數(shù)據(jù)
        if (address & 0x80) {
            GPIO_SetBits(MAX7219_DIN2_PORT, MAX7219_DIN2_PIN);
        } else {
            GPIO_ResetBits(MAX7219_DIN2_PORT, MAX7219_DIN2_PIN);
        }
        // 產(chǎn)生時(shí)鐘脈沖 1-0
        GPIO_SetBits(MAX7219_CLK2_PORT, MAX7219_CLK2_PIN);
        delay_us(1); // 延遲1微秒
        GPIO_ResetBits(MAX7219_CLK2_PORT, MAX7219_CLK2_PIN);
        delay_us(1); // 延遲1微秒
        address <<= 1;
    }

    // 發(fā)送數(shù)據(jù)字節(jié)
    for (i = 0; i < 8; i++) {
        // 設(shè)置DIN引腳數(shù)據(jù)位
        if (data & 0x80) {
            GPIO_SetBits(MAX7219_DIN2_PORT, MAX7219_DIN2_PIN);
        } else {
            GPIO_ResetBits(MAX7219_DIN2_PORT, MAX7219_DIN2_PIN);
        }
        // 產(chǎn)生時(shí)鐘脈沖 1-0
        GPIO_SetBits(MAX7219_CLK2_PORT, MAX7219_CLK2_PIN);
        delay_us(1); // 延遲1微秒
        GPIO_ResetBits(MAX7219_CLK2_PORT, MAX7219_CLK2_PIN);
        delay_us(1); // 延遲1微秒
        data <<= 1;
    }
}
//寫數(shù)據(jù)*********************************************************************
void MAX7219_Write1(uint8_t addr, uint8_t dat)
{
    MAX7219_CS1_0;
    SPI1_ReadWriteByte(addr,dat);
    MAX7219_CS1_1;
}
//寫數(shù)據(jù)*********************************************************************
void MAX7219_Write2(uint8_t addr, uint8_t dat)
{
    MAX7219_CS2_0;
    SPI2_ReadWriteByte(addr,dat);
    MAX7219_CS2_1;
}
/*
功能:初始化Max7219
參數(shù):-
介紹:有需求可自己調(diào)參,一般不需改動(dòng)
*/
void MAX7219_Init(void)
{
    
		MX_SPI1_Init();	
		MX_SPI2_Init();
    // 初始化 MAX7219
    MAX7219_Write1(0x09, 0x00);        // 譯碼方式:BCD碼
    MAX7219_Write1(0x0a, m_Intensity); // 亮度
    MAX7219_Write1(0x0b, 0x07);        // 掃描界限:8個(gè)數(shù)碼管顯示
    MAX7219_Write1(0x0c, 0x01);        // 掉電模式:0,普通模式:1
    MAX7219_Write1(0x0f, 0x00);        // 顯示測試:1;測試結(jié)束,正常顯示:0
		
    MAX7219_Write2(0x09, 0x00);        // 譯碼方式:BCD碼
    MAX7219_Write2(0x0a, m_Intensity); // 亮度
    MAX7219_Write2(0x0b, 0x07);        // 掃描界限:8個(gè)數(shù)碼管顯示
    MAX7219_Write2(0x0c, 0x01);        // 掉電模式:0,普通模式:1
    MAX7219_Write2(0x0f, 0x00);        // 顯示測試:1;測試結(jié)束,正常顯示:0
}

void MAX7219_IntensityAdd(void)
{
    if (m_Intensity < 0x0F)
    {
        m_Intensity++;
        MAX7219_Write1(0x0a, m_Intensity);
        MAX7219_Write2(0x0a, m_Intensity);
    }
}

void MAX7219_IntensityMinus(void)
{
    if (m_Intensity > 0)
    {
        m_Intensity--;
        MAX7219_Write1(0x0a, m_Intensity);
        MAX7219_Write2(0x0a, m_Intensity);
    }
}

void MAX7219_ShowMatrix(uint8_t M1[8][8], uint8_t M2[8][8])
{
    uint8_t i, j, dat;
    
    // 更新第一個(gè) MAX7219
    for (i = 0; i < 8; i++)
    {
        dat = (M1[i][0] << 7) | (M1[i][1] << 6) | (M1[i][2] << 5) | (M1[i][3] << 4) | (M1[i][4] << 3) | (M1[i][5] << 2) | (M1[i][6] << 1) | (M1[i][7] << 0);
        MAX7219_Write1(i+1 , dat); // 更新第一個(gè)模塊
    }
    // 更新第二個(gè) MAX7219
    for (i = 0; i < 8; i++)
    {
        dat = (M2[i][0] << 7) | (M2[i][1] << 6) | (M2[i][2] << 5) | (M2[i][3] << 4) | (M2[i][4] << 3) | (M2[i][5] << 2) | (M2[i][6] << 1) | (M2[i][7] << 0);
        MAX7219_Write2(i+1 , dat); // 更新第二個(gè)模塊
    }
}

void MX_SPI1_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;

    // 使能GPIOA時(shí)鐘
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE);
	

    // 配置CS引腳為推挽輸出模式
    GPIO_InitStructure.GPIO_Pin = MAX7219_CS1_PIN ;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(MAX7219_CS1_PORT, &GPIO_InitStructure);

    // 配置CLK引腳為推挽輸出模式
    GPIO_InitStructure.GPIO_Pin = MAX7219_CLK_PIN;
    GPIO_Init(MAX7219_CLK_PORT, &GPIO_InitStructure);

    // 配置DIN引腳為推挽輸出模式-Mosi
    GPIO_InitStructure.GPIO_Pin = MAX7219_DIN_PIN;
    GPIO_Init(MAX7219_DIN_PORT, &GPIO_InitStructure);

}

void MX_SPI2_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;

    // 使能GPIOA時(shí)鐘
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB , ENABLE);
	
	  // 配置CS引腳為推挽輸出模式
    GPIO_InitStructure.GPIO_Pin =  MAX7219_CS2_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(MAX7219_CS2_PORT, &GPIO_InitStructure);

    // 配置CLK引腳為推挽輸出模式
    GPIO_InitStructure.GPIO_Pin = MAX7219_CLK2_PIN;
    GPIO_Init(MAX7219_CLK2_PORT, &GPIO_InitStructure);

    // 配置DIN引腳為推挽輸出模式-Mosi
    GPIO_InitStructure.GPIO_Pin = MAX7219_DIN2_PIN;
    GPIO_Init(MAX7219_DIN2_PORT, &GPIO_InitStructure);



}

max7219.h

這里的 IO 口也可以自定義

#ifndef __SPI_H__
#define __SPI_H__

#include "stm32f10x.h"
//模擬SPI,如有需求自己改動(dòng)即可
#define MAX7219_CS1_PIN GPIO_Pin_4
#define MAX7219_CS1_PORT GPIOA

#define MAX7219_CLK_PIN GPIO_Pin_5
#define MAX7219_CLK_PORT GPIOA

#define MAX7219_DIN_PIN GPIO_Pin_6
#define MAX7219_DIN_PORT GPIOA

#define MAX7219_CS2_PIN GPIO_Pin_4
#define MAX7219_CS2_PORT GPIOB

#define MAX7219_CLK2_PIN GPIO_Pin_5
#define MAX7219_CLK2_PORT GPIOB

#define MAX7219_DIN2_PIN GPIO_Pin_6
#define MAX7219_DIN2_PORT GPIOB


#define     MAX7219_CS1_0     GPIO_ResetBits(MAX7219_CS1_PORT, MAX7219_CS1_PIN)
#define     MAX7219_CS1_1     GPIO_SetBits(MAX7219_CS1_PORT, MAX7219_CS1_PIN)

#define     MAX7219_CS2_0     GPIO_ResetBits(MAX7219_CS2_PORT, MAX7219_CS2_PIN)
#define     MAX7219_CS2_1     GPIO_SetBits(MAX7219_CS2_PORT, MAX7219_CS2_PIN)

void MAX7219_Init(void);
void MX_SPI1_Init(void);
void MX_SPI2_Init(void);

void MAX7219_ShowMatrix(uint8_t M1[8][8], uint8_t M2[8][8]);
void MAX7219_IntensityMinus(void);
void MAX7219_IntensityAdd(void);
// SPI1 讀寫一個(gè)字節(jié)
void SPI1_ReadWriteByte(uint8_t address, uint8_t data);

#endif /* __SPI_H__ */

?3.主代碼部分

main.c

實(shí)現(xiàn)設(shè)備的初始化和數(shù)據(jù)初始

#include "git.h"

// 軟件定時(shí)器設(shè)定
static Timer task1_id;
static Timer task2_id;
static Timer task3_id;
extern u8 time25ms;
extern uint8_t m_Mat1[8][8], m_Mat2[8][8];

// 獲取全局變量
const char *topics[] = {S_TOPIC_NAME};

// 硬件初始化
void Hardware_Init(void)
{
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // 設(shè)置中斷優(yōu)先級分組為組2:2位搶占優(yōu)先級,2位響應(yīng)優(yōu)先級

    delay_init(); // 延時(shí)函數(shù)初始化
    GENERAL_TIM_Init(TIM_4, 0, 1);
    Usart1_Init(115200); // 串口1初始化為115200

    Usart3_Init(115200); // 串口3,驅(qū)動(dòng)ESP8266用
    System_PB34_setIO();
    LED_Init();
    Key_GPIO_Config(); // key
    MAX7219_Init();    // MAX719
    Matrix_DispNumberOrLetterByIdx(m_Mat1, 23);
    Matrix_DispNumberOrLetterByIdx(m_Mat2, 25);
    MAX7219_ShowMatrix(m_Mat1, m_Mat2);
	
		IIC_Init();
    MPU6050_initialize(); // 陀螺儀
	
		printf("okn");
#if OLED                  // OLED文件存在
    OLED_Init();
    OLED_ColorTurn(0);   // 0正常顯示,1 反色顯示
    OLED_DisplayTurn(0); // 0正常顯示 1 屏幕翻轉(zhuǎn)顯示
#endif
    while (Reset_Threshole_Value(&threshold_value_init, &device_state_init) != MY_SUCCESSFUL)
        delay_ms(5); // 初始化閾值

#if OLED // OLED文件存在
    OLED_Clear();
#endif
}

// 任務(wù)1
void task1(void)
{
    // 1秒計(jì)算器
    Automation_Close();
		
}
// 任務(wù)2
void task2(void)
{
    Read_Data(&Data_init);   // 更新傳感器數(shù)據(jù)
    Update_device_massage(); // 更新設(shè)備

    State = ~State;
	
}

// 軟件初始化
void SoftWare_Init(void)
{
    // 定時(shí)器初始化
    timer_init(&task1_id, task1, 980, 1);           // 1s 執(zhí)行一次
    timer_init(&task2_id, task2, 50, 1); // (git里面設(shè)置) ms執(zhí)行一次


    timer_start(&task1_id);
    timer_start(&task2_id);

}
// 主函數(shù)
int main(void)
{

    unsigned char *dataPtr = NULL;
	  SoftWare_Init(); // 軟件初始化
    Hardware_Init(); // 硬件初始化


    // 啟動(dòng)提示
    Data_init.Beep = 100;

    TIM_Cmd(TIM4, ENABLE); // 使能計(jì)數(shù)器
    while (1) {

        // 線程
        timer_loop(); // 定時(shí)器執(zhí)行

#if KEY_OPEN
        // 按鍵監(jiān)測
        if (time25ms == MY_TRUE) {
            Check_Key_ON_OFF();
            time25ms = MY_FALSE;
        }
#endif
    }
}

?代碼主要實(shí)現(xiàn)部分

// 更新設(shè)備狀態(tài)
mySta Update_device_massage()
{
	// 模式
	if (m_Mode == 0)
	{
		Matrix_DispNumberOrLetterByIdx(m_Mat1, m_DropDelay);
		Matrix_DispNumberOrLetterByIdx(m_Mat2, Data_init.Wait_Time); // T
	}
	else if (m_Mode == 1) // 漏沙模式
	{
		m_Moved = Update_Matrix();
		
		if (m_FrameCounter >=1000/Data_init.Time *m_DropDelay || (m_DropDelay == 21 && m_FrameCounter >= 1000/Data_init.Time))
		{
			if (m_Dropped){
				m_FrameCounter = 0;
			}
		}
		if (m_DropDelay == 21 && m_Moved == 0 && m_Dropped == 0) // 漏沙循環(huán)
		{
			if( Data_init.ball_num == 60){
				Data_init.ball_num =0;
			}
			if (Is_Matrix_Empty(m_Mat1) && m_Rotation == 0)
			{
				Matrix_Fill(m_Mat1);
				m_Mat1[0][0] = 0;
				m_Mat1[0][1] = 0;
				m_Mat1[1][0] = 0;
				m_Mat1[1][1] = 0;
				Matrix_Clear(m_Mat2);
			}
			else if (Is_Matrix_Empty(m_Mat2) && m_Rotation == 180)
			{
				Matrix_Fill(m_Mat2);
				m_Mat2[0][0] = 0;
				m_Mat2[0][1] = 0;
				m_Mat2[1][0] = 0;
				m_Mat2[1][1] = 0;
				Matrix_Clear(m_Mat1);
			}
		}
		else if (Data_init.ball_num >= 60 && m_Moved == 0 && m_Dropped == 0 && (m_Rotation == 0 || m_Rotation == 180)) // 漏沙結(jié)束后切換到模式2
		{
			Data_init.Beep = 500;
			m_FrameCounter = 0;
			m_Mode = 2;
		}
	}
	else if (m_Mode == 2) // 待機(jī)眨眼動(dòng)畫
	{
		if (m_FrameCounter >= 1000 / 66 * m_BlinkDelay)
		{
			Blink();
			m_BlinkDelay = rand() % 5 + 5;
			m_FrameCounter = 0;
			
		}
		else{
			OpenEyes();
		}
			
	}
	if(Data_init.ball_num == 60 && m_DropDelay != 21){
		Data_init.Beep = 25;
	}

	// 循環(huán) / 定時(shí)
	if(Data_init.Flage == 1){
		m_DropDelay = 21;
	}else{
		m_DropDelay = 23;
	}
	MAX7219_ShowMatrix(m_Mat1, m_Mat2);
	m_FrameCounter++;

	return MY_SUCCESSFUL;
}

四 程序說明

按鍵說明

按鍵有長短按模式
長按可以切換模擬,短按可以設(shè)置記時(shí)長 時(shí)長為 1 - 20 min可調(diào)

1.沙漏模式

以下圖為例:上面為無窮大 表示循環(huán)沙漏模式 下面的 1 表示定時(shí)時(shí)間為1 min

2.定時(shí)模式

以下圖為例:上面為愛心 表示定時(shí)沙漏模式 下面的 1 表示定時(shí)時(shí)間為1 min,時(shí)間到了之后會(huì)主動(dòng)蜂鳴器報(bào)警

五 參考

Arduino程序設(shè)計(jì)(十)8×8 共陰極LED點(diǎn)陣顯示(MAX7219)https://blog.csdn.net/weixin_44887565/article/details/132803275?ops_request_misc=%257B%2522request%255Fid%2522%253A%25223b76ef48626591536727ad003b02259d%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=3b76ef48626591536727ad003b02259d&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduend~default-1-132803275-null-null.142^v101^pc_search_result_base9&utm_term=max7219%E6%A8%A1%E5%9D%97&spm=1018.2226.3001.4187https://blog.csdn.net/weixin_44887565/article/details/132803275?ops_request_misc=%257B%2522request%255Fid%2522%253A%25223b76ef48626591536727ad003b02259d%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=3b76ef48626591536727ad003b02259d&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduend~default-1-132803275-null-null.142^v101^pc_search_result_base9&utm_term=max7219%E6%A8%A1%E5%9D%97&spm=1018.2226.3001.4187https://blog.csdn.net/weixin_44887565/article/details/132803275?ops_request_misc=%257B%2522request%255Fid%2522%253A%25223b76ef48626591536727ad003b02259d%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=3b76ef48626591536727ad003b02259d&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduend~default-1-132803275-null-null.142^v101^pc_search_result_base9&utm_term=max7219%E6%A8%A1%E5%9D%97&spm=1018.2226.3001.4187https://blog.csdn.net/weixin_44887565/article/details/132803275?ops_request_misc=%257B%2522request%255Fid%2522%253A%25223b76ef48626591536727ad003b02259d%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=3b76ef48626591536727ad003b02259d&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduend~default-1-132803275-null-null.142^v101^pc_search_result_base9&utm_term=max7219%E6%A8%A1%E5%9D%97&spm=1018.2226.3001.4187MPU-6050詳解https://blog.csdn.net/qq_30150579/article/details/136151474?ops_request_misc=%257B%2522request%255Fid%2522%253A%25224cc25091c4627d650c9a33a84e1baf9c%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=4cc25091c4627d650c9a33a84e1baf9c&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduend~default-1-136151474-null-null.142^v101^pc_search_result_base9&utm_term=MPU-6050%E6%A8%A1%E5%9D%97&spm=1018.2226.3001.4187https://blog.csdn.net/qq_30150579/article/details/136151474?ops_request_misc=%257B%2522request%255Fid%2522%253A%25224cc25091c4627d650c9a33a84e1baf9c%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=4cc25091c4627d650c9a33a84e1baf9c&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduend~default-1-136151474-null-null.142^v101^pc_search_result_base9&utm_term=MPU-6050%E6%A8%A1%E5%9D%97&spm=1018.2226.3001.4187https://blog.csdn.net/qq_30150579/article/details/136151474?ops_request_misc=%257B%2522request%255Fid%2522%253A%25224cc25091c4627d650c9a33a84e1baf9c%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=4cc25091c4627d650c9a33a84e1baf9c&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduend~default-1-136151474-null-null.142^v101^pc_search_result_base9&utm_term=MPU-6050%E6%A8%A1%E5%9D%97&spm=1018.2226.3001.4187https://blog.csdn.net/qq_30150579/article/details/136151474?ops_request_misc=%257B%2522request%255Fid%2522%253A%25224cc25091c4627d650c9a33a84e1baf9c%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=4cc25091c4627d650c9a33a84e1baf9c&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduend~default-1-136151474-null-null.142^v101^pc_search_result_base9&utm_term=MPU-6050%E6%A8%A1%E5%9D%97&spm=1018.2226.3001.4187

聯(lián)系方式 微信號(hào):13648103287

  • 聯(lián)系方式.docx
    下載
意法半導(dǎo)體

意法半導(dǎo)體

意法半導(dǎo)體(ST)集團(tuán)于1987年6月成立,是由意大利的SGS微電子公司和法國Thomson半導(dǎo)體公司合并而成。1998年5月,SGS-THOMSON Microelectronics將公司名稱改為意法半導(dǎo)體有限公司。意法半導(dǎo)體是世界最大的半導(dǎo)體公司之一,公司銷售收入在半導(dǎo)體工業(yè)五大高速增長市場之間分布均衡(五大市場占2007年銷售收入的百分比):通信(35%),消費(fèi)(17%),計(jì)算機(jī)(16%),汽車(16%),工業(yè)(16%)。 據(jù)最新的工業(yè)統(tǒng)計(jì)數(shù)據(jù),意法半導(dǎo)體是全球第五大半導(dǎo)體廠商,在很多市場居世界領(lǐng)先水平。例如,意法半導(dǎo)體是世界第一大專用模擬芯片和電源轉(zhuǎn)換芯片制造商,世界第一大工業(yè)半導(dǎo)體和機(jī)頂盒芯片供應(yīng)商,而且在分立器件、手機(jī)相機(jī)模塊和車用集成電路領(lǐng)域居世界前列.

意法半導(dǎo)體(ST)集團(tuán)于1987年6月成立,是由意大利的SGS微電子公司和法國Thomson半導(dǎo)體公司合并而成。1998年5月,SGS-THOMSON Microelectronics將公司名稱改為意法半導(dǎo)體有限公司。意法半導(dǎo)體是世界最大的半導(dǎo)體公司之一,公司銷售收入在半導(dǎo)體工業(yè)五大高速增長市場之間分布均衡(五大市場占2007年銷售收入的百分比):通信(35%),消費(fèi)(17%),計(jì)算機(jī)(16%),汽車(16%),工業(yè)(16%)。 據(jù)最新的工業(yè)統(tǒng)計(jì)數(shù)據(jù),意法半導(dǎo)體是全球第五大半導(dǎo)體廠商,在很多市場居世界領(lǐng)先水平。例如,意法半導(dǎo)體是世界第一大專用模擬芯片和電源轉(zhuǎn)換芯片制造商,世界第一大工業(yè)半導(dǎo)體和機(jī)頂盒芯片供應(yīng)商,而且在分立器件、手機(jī)相機(jī)模塊和車用集成電路領(lǐng)域居世界前列.收起

查看更多

相關(guān)推薦

方案定制

去合作
方案開發(fā)定制化,2000+方案商即時(shí)響應(yīng)!

方案定制,程序設(shè)計(jì)方案、單片機(jī)程序設(shè)計(jì)與講解、APP定制開發(fā)。本公眾號(hào)致力于向讀者傳遞關(guān)于程序設(shè)計(jì)和開發(fā)的相關(guān)知識(shí),并分享一些關(guān)于軟件開發(fā)的最佳實(shí)踐。如果您有什么問題或建議,請隨時(shí)聯(lián)系我們。我們將竭誠為您服務(wù)