丐版电子沙漏

 只是想简单地用8*8LED点阵实现一下类电子沙漏的东西。没有陀螺仪,没有改变方向自动找平的功能,只实现最简单的下落堆积的功能。对,就是个伪电子沙漏,那么开始吧...

主控:CH32V307ce9aa568358f41189edac74dcc1c9d3d.jpg

 8*8点阵驱动:2个595b699cb47460b4cd899cfd62b3e0798a2.jpg

 这个模块级联没有引出

 一、源码

/********************************** (C) COPYRIGHT *******************************
* File Name          : main.c
* Author             : WCH
* Version            : V1.0.0
* Date               : 2021/06/06
* Description        : Main program body.
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for 
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/


#include "debug.h"


/*在中断里面调用的变量需要使用 volatile 修饰*/
volatile uint8_t gpio_interrupt_flag=0;

/* Global typedef */
/* 595 这里只定义了1个595的3个pin,应该有第2个595,实现从上面的沙漏到下一沙漏,我暂时只用了1个595,每次只显示上面或下面一个沙漏*/
#define LED_SER GPIO_Pin_13
#define LED_RCK GPIO_Pin_14
#define LED_SRCK GPIO_Pin_15


#define LED_SER_SET GPIO_WriteBit(GPIOB, LED_SER,Bit_SET)
#define LED_SER_CLR GPIO_WriteBit(GPIOB, LED_SER,Bit_RESET)

#define LED_SRCK_SET GPIO_WriteBit(GPIOB, LED_SRCK,Bit_SET)
#define LED_SRCK_CLR GPIO_WriteBit(GPIOB, LED_SRCK,Bit_RESET)

#define LED_RCK_SET GPIO_WriteBit(GPIOB, LED_RCK,Bit_SET)
#define LED_RCK_CLR GPIO_WriteBit(GPIOB, LED_RCK,Bit_RESET)

/* Global define */

//用两个数组分布代表上下2个沙漏的数据,低电平点亮
//可以理解为显存,每个显存8个字节,8*8=64bit,对应8*8LED的64个点
u8 matrix1[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
u8 matrix2[8]={0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};


//由于LED的COM和SEG都是595控制,需要定义COM的控制数据,用于点亮一行,高电平有效
//0x01代表第一个行,以此类推
const u8 pos[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};


/* Global Variable */
/*
*    @prief GPIO初始化
*/
void LED_GPIO_Init(void)
{
   GPIO_InitTypeDef GPIO_InitStructure = {0};
   NVIC_InitTypeDef NVIC_InitStructure = {0};
   EXTI_InitTypeDef EXTI_InitStructure = {0};

   RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
   GPIO_InitStructure.GPIO_Pin = LED_SER|LED_RCK|LED_SRCK;

   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
   GPIO_Init(GPIOB, &GPIO_InitStructure);

   RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO |RCC_APB2Periph_GPIOA, ENABLE);

   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
   GPIO_Init(GPIOA, &GPIO_InitStructure);



   /*设置PA2作为中断线的GPIO引脚*/
   GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource2);

   /*设置GPIO中断*/
   EXTI_InitStructure.EXTI_Line = EXTI_Line0;//中断线0
   EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//中断模式
   EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;//下降沿触发
   EXTI_InitStructure.EXTI_LineCmd = ENABLE;//使能
   EXTI_Init(&EXTI_InitStructure);

   /*配置中断优先等级*/
   NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;//外部中断0
   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;//抢占式优先级
   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;//响应式优先级
   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能
   NVIC_Init(&NVIC_InitStructure);
}


/**
* @brief  中断函数
*    按键中断和沙漏无关
**/
__attribute__((interrupt("WCH-Interrupt-fast"))) //中断函数前加这上这句,告诉编译器这个是中断函数
void EXTI0_IRQHandler(void)
{
  if(EXTI_GetITStatus(EXTI_Line0)!=RESET)//产生中断
  {
      gpio_interrupt_flag=1;
      EXTI_ClearITPendingBit(EXTI_Line0);//清除中断标志
  }
}

/*
 * @prief 控制595串行输入
 *  PN:反显
 * */
void HC595(u8 c,u8 PN)
{
    u8 i;
    for(i=0;i<8;i++){

        if(PN==0){                       //正常显示
            if((c>>i) & 0x01) LED_SER_SET;
            else LED_SER_CLR;
        }
        else{                                //反显
            if((c>>i) & 0x01) LED_SER_CLR;
            else LED_SER_SET;
        }

        LED_SRCK_CLR;
        LED_SRCK_SET;     // 上升沿进行一次数据移入
    }
}

/*
*    @prief 显示pBuff指向的8个字节数据的内容到8*8led
*
*/
void Matrix8x8(u8 *pBuff)
{
    unsigned char k;
    unsigned int m,n;

       for(m=0;m<32;m++)    //为移动预留
       {
           for(n=0;n<32;n++)//控制显示速度,防止闪烁
           {
               for(k=0;k<8;k++)   //行扫描
               {
                   HC595(~pos[k],0);
                   HC595(~pBuff[k],0);
                   Delay_Us(10);

                   LED_RCK_CLR;
                   LED_RCK_SET;    //并行输出

                }

            }
       }
}



/*
* @prief 上沙漏最下一个点不断闪烁
*/
void sandflash(u8 bright)
{
    u8 oldVal=matrix1[7];
    if(bright==1){
        matrix1[7]=(0x7F&oldVal)|0x80;
        Matrix8x8(matrix1);
    }else{
        matrix1[7]=0x7F&oldVal;
        Matrix8x8(matrix1);
    }
    matrix1[7]=oldVal; // 
}


/*
* @prief 初始化沙漏
* @param matrix:8字节显存;val:初始的内容
*/
void resetHourglass(u8 *matrix,u8 val)
{
    u8 i;
    for(i=0;i<8;i++){
        matrix[i]=val;
    }
}

/*
*    @prief 上沙漏演示
*/
void hourglass1()
{
    u8 i,j;
    for(j=0;j<15;j++){        //上沙漏,需要循环14次,将沙子漏完
        if(j<8){              //上8个和后面处理不同

            for(i=0;i<=j/2;i++){    //分成2部分

                sandflash(1);
                matrix1[i] =(matrix1[i] << 1) | 0x01;    //左半部分处理,就是左移,或上第1位
                Matrix8x8(matrix1);
                sandflash(0);

                if(i!=j%8-i){            //如果前面没处理,那么执行
                sandflash(1);
                matrix1[j%8-i] =(matrix1[j%8-i] << 1) | 0x01;    //右半部分,也是就是左移,或上第1位
                Matrix8x8(matrix1);
                sandflash(0);
                }
            }

        }
        else{


            for(i=0;i<((7-j%8)-1)/2+1;i++){    //上沙漏,下半部分处理,也是分左右两半
                sandflash(1);
                matrix1[i+j%8+1] =(matrix1[i+j%8+1] << 1) | 0x01;    //左移,或上第1位
                Matrix8x8(matrix1);
                sandflash(0);

                if(i+j%8+1!=j-(i+j%8+1)){
                sandflash(1);
                matrix1[j-(i+j%8+1)] =(matrix1[j-(i+j%8+1)] << 1) | 0x01;    //左移,或上第1位
                Matrix8x8(matrix1);
                sandflash(0);
                }
            }
        }

    }

}


/*
*    @prief 下沙漏一个沙子向下落
*/
void sandflow(u8 step)
{
    u8 i;
    for(i=0;i<step;i++){            //step是下落步数
        matrix2[i]=matrix2[i]&~(0x01<<i);        //显示
        Matrix8x8(matrix2);
        matrix2[i]=matrix2[i]|(0x01<<i);         //消隐
        Matrix8x8(matrix2);
    }
}

/*
*    @prief 下沙漏演示
*    点亮低电平有效
*/
void hourglass2(void)
{
    u8 i,j;

    for(i=0;i<8;i++){
        for(j=0;j<i;j++)
        {
            sandflow(8-i);
            matrix2[7-j]=matrix2[7-j]&~(0x80>>i);        //每一行都要设置一个(0x80>>i)
            Matrix8x8(matrix2);
            sandflow(8-i);
            matrix2[7-i]=matrix2[7-i]&~(0x80>>j);        //第7-i行要设置(0x80>>j)
            Matrix8x8(matrix2);
        }
        sandflow(8-i);
        matrix2[7-i]=matrix2[7-i]&~(0x80>>i);            //第7-i行也要设置一个(0x80>>i)
        Matrix8x8(matrix2);
    }

}



/*********************************************************************
 * @fn      main
 *
 * @brief   Main program.
 *
 * @return  none
 */
int main(void)
{

	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	SystemCoreClockUpdate();
	Delay_Init();
	USART_Printf_Init(115200);	
	printf("SystemClk:%d\r\n",SystemCoreClock);
	printf( "ChipID:%08x\r\n", DBGMCU_GetCHIPID() );
	printf("This is printf example\r\n");


	LED_GPIO_Init();

	while(1)
    {
        /*按键中断,预留,和沙漏演示无关*/
	    if (gpio_interrupt_flag==1) {//有中断产生
            gpio_interrupt_flag=0;
        }
        
        //上沙漏演示
        hourglass1();
        //初始化上沙漏显存
        resetHourglass(matrix1,0x00);
        //下沙漏演示
        hourglass2();
        //初始化下沙漏显存
        resetHourglass(matrix2,0xFF);
	}
}

二、演示

fc1dcad5dd23466bacef598f6bb98555.jpeg

沙漏演示2

沙漏演示

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值