📄 meteor.c
字号:
/****************************************Copyright (c)****************************************************
** LED Incorporated Co.,LTD.
**
** http://www.ledinc.biz
**
**------------------------------------- File Info --------------------------------------------------------
** File Name : Meteor.c
** Hardware : MCU = AT89C2051; Fosc = 24MHz
** Compiler : C51
**
**------------------------------------ Version Info ------------------------------------------------------
** Create By : Raymond
** Create Date : 09-04-09
** Version : 1.00
** Description :
** 1. 随机速度、流星长度;
** 2. 定时器0产生随机种子;
** 3. 淡入淡出效果;
** 4. 梯形算法产生流星头亮尾暗的效果;
** 5. 发现问题:亮度不够,因为每次都是等所有的LED灭了以后再移位的,总体上看LED点亮的时间比列不高。
**--------------------------------------------------------------------------------------------------------
** Modify By : Raymond
** Modify Date : 09-04-13
** Version : 1.01
** Description :
** 1. 解决梯形算法的一个bug:当流星长度Len为1时,除数(Len-1)为零;
** 2. 移位应该进行16+1次,不然最后1bit会残留在流星管上,这在Len=1时表现突出;
** 3. 随机函数有待改进,发现Len=1的重复周期总在6次到8次左右;
**--------------------------------------------------------------------------------------------------------
** Modify By : Raymond
** Modify Date : 09-04-13
** Version : 2.00
** Description :
** 1. 优化梯形算法(多米诺骨牌算法,Domino),增加亮度以及平滑度;
** 2. 改进随机函数,使输出数据更加随机;
**
**--------------------------------------------------------------------------------------------------------
** Modify By : Raymond
** Modify Date : 09-04-15
** Version : 2.01
** Description :
** 1. 从STC12C4510AD移植到AT89C2051,管脚有变化,且STC是1T时钟,更快,定时相关的需要修改;
** 2. 当随机算法相同时,伪随机数的种子决定出现的随机数;
** 3. 修改软件,使用捕捉RC充电常数来决定随机种子,硬件方面把RC中的电容接到Vcc,电阻接到GND,RC节点连到INT1
** 即外部中断1,使用下降沿触发,捕捉定时器0(因为是8位随机数,故只捕捉TL0);当RC值足够大时,实际效果可以做到
** 每次上电后的第一次都不一样,即硬件非伪随机。
**
**--------------------------------------------------------------------------------------------------------
** Modify By : Raymond
** Modify Date : 09-04-16
** Version : 2.02
** Description :
** 1. 细调时间参数、增加闪烁间隔时间的随机数量;
**
*********************************************************************************************************/
#include "reg51.h"
#include <stdio.h>
#define uchar unsigned char
#define uint unsigned int
#define NOP() /*Delay(1) */
#define EnableInterrupt() EA = 1
#define DisableInterrupt() EA = 0
/* PIN define */
sbit LATCH = P3^0;
sbit CLK = P3^1;
sbit SDA = P3^2;
typedef struct{
unsigned char MeteorLen; //流星长度
unsigned char Speed; //下降速度,数组越大速度越慢
} METEOR;
//-------------Config Parameter-------------
#define SPEED_MAX_GRAD 8
#define LEN_MAX_GRAD 5
#define INTERVAL_MAX_GRAD 10
#define METEOR_MAX_NUM (5*10)
//-------------Global Variables-------------
METEOR code MeteorTable[METEOR_MAX_NUM] = {
{1,40}, {1,50}, {1,60}, {1,70}, {1,80},
{2,15}, {2,20}, {2,20}, {2,25}, {2,30},
{3,10}, {3,12}, {3,15}, {3,17}, {3,20},
{4,7}, {4,10}, {4,13}, {4,17}, {4,20},
{5,5}, {5,8}, {5,11}, {5,14}, {5,18},
{6,4}, {6,7}, {6,10}, {6,13}, {6,16},
{7,4}, {7,6}, {7,8}, {7,10}, {7,12},
{8,2}, {8,4}, {8,7}, {8,9}, {8,9},
{9,1}, {9,3}, {9,5}, {9,7}, {9,8},
{10,1}, {10,3}, {10,5}, {10,6}, {10,7}
};
unsigned char code DispTable[LEN_MAX_GRAD] = {0x0F, 0x1F, 0x3F, 0x7F, 0xFF};
//length table, 4 grads of length
unsigned char code IntervalTable[INTERVAL_MAX_GRAD] = {20, 40, 60, 80, 100, 120, 140, 160, 180, 200};
//interval table
unsigned char FlagRandStarted;
unsigned char RAND_SEED; //the random seed, to generate a random number
unsigned char Cnt10ms, Cnt10us;
#define CNT10MS 20000
#define CNT1US 35
//-------------Function define-------------
void SPI_SendWord(unsigned int);
/*********************************************************************************************************
** Function : Delay
** Input : t
** Output : none
** Return : none
** Description : Delay. soft delay
**
*********************************************************************************************************/
void Delay(uchar t)
{
uint j;
while(t--){
j = 1000;
while(j--);
}
}
/*********************************************************************************************************
** Function : RandomStart
** Input : none
** Output : none
** Return : none
** Description : Initialize the random seed, select TIMER0 as the source
**
*********************************************************************************************************/
void RandomStart(void)
{
char i;
FlagRandStarted = 0;
TL0 = 0;
TH0 = 0;
RAND_SEED = 0;
TR0 = 1; //startup TIMER0
IT1 = 1; //falling edge active (edge triggered)
EX1 = 1;
EA = 1;
i = 0;
while(!FlagRandStarted){
Delay(1);
SPI_SendWord(0x0000);
if(++i>100){ //超时,没有RC充电电路
RAND_SEED = TL0;
SPI_SendWord(0xFFFF);
Delay(50);
break;
}
}
//RAND_SEED = 11;
EX1 = 0;
EA = 0;
TR0 = 0; //stop TIMER0
}
/*********************************************************************************************************
** Function : ISR_INT1
** Input : none
** Output : none
** Return : none
** Description : Interrupt Serve Routine for External Interrupt 1.
** use for initialize the random seed with TL0
**
*********************************************************************************************************/
void ISR_INT1(void) interrupt 2
{
RAND_SEED = TL0; //initialize the random seed
FlagRandStarted = 1;
}
/*********************************************************************************************************
** Function : Random
** Input : none
** Output : none
** Return : A random number
** Description : Get a random number, 8 bit integer
**
*********************************************************************************************************/
unsigned char Random(void)
{
//RAND_SEED = TL0;
RAND_SEED = RAND_SEED*13 + 3;
return(RAND_SEED);
}
/*********************************************************************************************************
** Function : Port_Init
** Input : none
** Output : none
** Return : none
** Description : Initialize the IO port
**
*********************************************************************************************************/
void Port_Init(void)
{
LATCH = 0;
CLK = 0;
SDA = 0;
}
/*********************************************************************************************************
** Function : Delay10ms
** Input : t
** Output : none
** Return : none
** Description : Delay 10*t ms. Use TIMER1, Mode 1(16 bit)
**
*********************************************************************************************************/
void Delay10ms(uchar t)
{
if(t==0) return;
Cnt10ms = t;
TH1 = (65536-CNT10MS)/256; // 8MHz,1T,8000个时钟周期,定时时间为1ms
TL1 = (65536-CNT10MS)%256;
TF1 = 0;
TR1 = 1; // 开定时器
ET1 = 1; // 允许定时器1中断
while(Cnt10ms);
TR1 = 0; // 关定时器1
ET1 = 0; // 禁止定时器1中断
}
/*********************************************************************************************************
** Function : Delay10us
** Input : t
** Output : none
** Return : none
** Description : Delay 10*t us. Use TIMER0, Mode 2(8 bit autoload)
**
*********************************************************************************************************/
void Delay10us(uchar t)
{
if(t==0) return;
Cnt10us = t;
TH0 = (256-CNT1US); // 2MHz,1T,80个时钟周期,定时时间为10us
TF0 = 0;
TR0 = 1; // 开定时器
ET0 = 1; // 允许定时器0中断
while(Cnt10us);
TR0 = 0; // 关定时器0
ET0 = 0; // 禁止定时器0中断
}
/*********************************************************************************************************
** Function : ISR_Timer0
** Input : none
** Output : none
** Return : none
** Description : Interrupt Serve Routine for TIMER0.
** TIMER0 config as Mode 2(8 bit autoload), clock is
**
*********************************************************************************************************/
void ISR_Timer0(void) interrupt 1
{
TF0 = 0;
if(Cnt10us>0){
Cnt10us--;
}
}
/*********************************************************************************************************
** Function : ISR_Timer1
** Input : none
** Output : none
** Return : none
** Description : Interrupt Serve Routine for TIMER1.
** TIMER1 config as Mode 1(16 bit), clock is
**
*********************************************************************************************************/
void ISR_Timer1(void) interrupt 3
{
TF1 = 0;
TH1 = (65536-CNT10MS)/256; //8MHz,1T,8000个时钟周期,定时时间为1ms
TL1 = (65536-CNT10MS)%256;
if(Cnt10ms>0){
Cnt10ms--;
}
}
/*********************************************************************************************************
** Function : Timer_Init
** Input : none
** Output : none
** Return : none
** Description : Initialize the timers(TIMER0 and TIMER1)
**
*********************************************************************************************************/
void Timer_Init(void)
{
//AUXR |= 0xC0; //T0,T1速度为12倍标准51
TMOD |= 0x12; // 定时器0为8位自动重装计数器,定时器1为16位计数器
//TF0 = 0;
//TF1 = 0;
//TR0 = 1; // 开定时器
//ET0 = 1; // 允许定时器0中断
//ET1 = 1; // 允许定时器1中断
}
/*********************************************************************************************************
** Function : SPI_SendWord
** Input : Data -> data to be sent
** Output : none
** Return : none
** Description : Send a 16 bit data by the SPI interface(soft SPI)
**
*********************************************************************************************************/
void SPI_SendWord(uint Data)
{
uchar i, Buf;
LATCH = 0;
Buf = (uchar)(Data>>8); //High byte
for(i = 0; i < 8; i++){
CLK = 0;
if(Buf & 0x80) {
SDA = 1;
} else {
SDA = 0;
}
CLK = 1;
Buf <<= 1;
NOP();
}
Buf = (uchar)Data; //Low byte
for(i = 0; i < 8; i++){
CLK = 0;
if(Buf & 0x80) {
SDA = 1;
} else {
SDA = 0;
}
CLK = 1;
Buf <<= 1;
NOP();
}
LATCH = 1;
}
#define Tmax 4
/*********************************************************************************************************
** Function : Flash
** Input : none
** Output : none
** Return : none
** Description : Display one time of meteor falling
**
*********************************************************************************************************/
void Flash(void)
{
char i, j, k;
unsigned char dT, DelayMax;
unsigned char Speed, Len; //the fall speed and the length of meteor
unsigned char FlagOver;
unsigned int DispBuf;
unsigned char BitDelay[16], DelayBuf[16];
i = Random() % METEOR_MAX_NUM;
Len = MeteorTable[i].MeteorLen; //get the falling speed of meteor
Speed = MeteorTable[i].Speed;
/*******************
Len = 3;
Speed = 10; */
/********************/
DelayMax = Len*Tmax; //????
for(i = 0; i < 16; i++){
BitDelay[i] = 0;
}
BitDelay[0] = DelayMax;
if(Len == 1){
dT = Tmax - 1;
} else {
dT = Tmax;
}
//dT = 5;
FlagOver = 0;
while(1){
for(j = 0; j < 16; j++){
if(BitDelay[j] > 0){
BitDelay[j]--;
}
}
//for(j = 0; j < 16; j++){ //注意数组越界
for(j = 0; j < 15; j++){
if( BitDelay[j] == DelayMax-dT){
BitDelay[j+1] = DelayMax; //触发下一位
}
DelayBuf[j] = BitDelay[j];
}
DelayBuf[15] = BitDelay[15];
if(BitDelay[15] == DelayMax){ //MSB开始点亮
FlagOver = 1;
}
if(FlagOver & (BitDelay[15] == 0)){ //MSB熄灭
break;
}
for(j = 0; j < DelayMax; j++){
DispBuf = 0;
for(k = 0; k < 16; k++){
if(DelayBuf[k]>0){
DelayBuf[k]--;
DispBuf |= (1 << k);
}
}
SPI_SendWord(DispBuf);
Delay10us(Speed); //control the falling speed of meteor
}
}
SPI_SendWord(0x0000); //clear display
}
/*********************************************************************************************************
** Function : IntervalBetweenFlash
** Input : none
** Output : none
** Return : none
** Description : Delay a certain time between two flash
**
*********************************************************************************************************/
void IntervalBetweenFlash(void)
{
unsigned char i;
unsigned char Interval; //the interval between the two meteor-falling
i = Random() % INTERVAL_MAX_GRAD; //get the index of the interval table
Interval = IntervalTable[i]; //40~200
Delay10ms(Interval);
Delay10ms(Interval);
}
/*********************************************************************************************************
** Function : main
** Input : none
** Output : none
** Return : none
** Description : the main function that is a endless loop
**
*********************************************************************************************************/
void main(void)
{
RandomStart();
Port_Init();
SPI_SendWord(0x0000); //Clear display
Timer_Init();
EnableInterrupt();
while(1)
{
Flash();
IntervalBetweenFlash();
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -