51hei团团 发表于 2021-2-28 23:44
干的漂亮,能分享下程序吗?
/*
*32只WS2812+滚珠开关制作的摇摇棒*
*演示在上方16个LED上显示“你真棒”三个汉字
*CPU:HC89S003F4 16K bytes flash ROM, 256+256 bytes data RAM
*WS2812 接P22(推挽驱动) ,滚珠开关接P00(下降沿中断方式)
*晶振频率:32MHz,Fosc 16MHz
*程序版本:V1.00
*硬件平台:003F4 V1.00
*编写软件:Keil uVision4
*编写:xxd0708
*声明:本程序只供学习使用,未经作者许可,不得用于其它任何用途
*/
#define ALLOCATE_EXTERN
#include "HC89S003F4.h"
#include <intrins.h>
/**********************************************************
程序名称:LED摇摇棒显示64*16像素
简要说明:外部中断方式INT0显示;取模方式:纵向取模、字节倒序
(取点方式:纵向8点上高位,字节排列:上到下左到右)
**********************************************************/
sbit WS2812_IO = P2^2 ;
u8 KY; //防止重影的控制变量
u8 cont_rock=0;
u8 cont_col=0;
u8 col_r,col_g,col_b;
// 你(0) 真(1) 棒(2)
code u8 dat_word1[]=
{
0x00,0x80,0x01,0x00,0x06,0x00,0x1F,0xFF,0xE0,0x00,0x02,0x08,0x04,0x30,0x18,0xC0,
0xF0,0x02,0x10,0x01,0x13,0xFE,0x10,0x00,0x10,0x80,0x14,0x60,0x18,0x18,0x00,0x00,/*"你",3*/
0x00,0x08,0x20,0x08,0x20,0x09,0x2F,0xFA,0x2A,0xAC,0x2A,0xA8,0x2A,0xA8,0xFA,0xA8,
0x2A,0xA8,0x2A,0xA8,0x2A,0xAC,0x2F,0xFA,0x20,0x09,0x20,0x08,0x00,0x08,0x00,0x00,/*"真",4*/
0x08,0x20,0x08,0xC0,0x0B,0x00,0xFF,0xFF,0x09,0x00,0x08,0x80,0x22,0x48,0x2A,0x88,
0x2B,0x28,0x2E,0x28,0xFA,0xFF,0x2A,0x28,0x2B,0x28,0x2A,0x88,0x22,0x48,0x00,0x00,/*"棒",5*/
};
//延时子函数-16Mhz 1ms延时
void delayMs_16Mhz(u16 ms)
{
u16 j;
for(; ms>0; ms--)
for(j=1596; j>0; j--);
}
//延时函数-16Mhz 1us延时
void delayUs_16Mhz(u8 us)
{
for(; us>0; us--)
{
_nop_();
_nop_();
_nop_();
}
}
void ws2812_rst(void)
{
WS2812_IO = 0;
delayUs_16Mhz(80);
}
void ws2812_write_byte( u8 dat)
{
u8 i = 8;
dat <<= 1; //最高位进入CY
while(i)
{
//高电平时间小于0.45uS为逻辑0,大于时为逻辑1
WS2812_IO = 1;
//如果主频较高可在此处适当增加_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
WS2812_IO = CY;
_nop_();
_nop_();
_nop_();
_nop_();
//如果主频较高可在此处适当增加_nop_();
WS2812_IO = 0; //位发送完保持低电平,时间不大于50us。否则复位
_nop_();
_nop_();
_nop_();
_nop_();
dat <<= 1; //最高位进入CY
i--;
}
}
/*显示关闭*/
void display_off(void)
{
uchar i;
i=0;
while( i< 32 )
{
ws2812_write_byte( 0x00);
ws2812_write_byte( 0x00);
ws2812_write_byte( 0x00);
i++;
}
ws2812_rst();
}
/*显示子程序 在上方16个LED上显示三个汉字*/
void display_3word(void)
{
uchar i,j,temp;
//ws2812_rst();
i=0;
j=0;
while(j<96) //3个汉字3*16*2个字节
{
i=0;
while( i< 16 ) //下16不显示 可修改
{
//与普通LED主要更改点,有显示时发三个分量数据,否则发三个0
ws2812_write_byte( 0x00);
ws2812_write_byte( 0x00);
ws2812_write_byte( 0x00);
i++;
}
temp = dat_word1[j+1];//上方16位先送第二字节(依取模方式而定)
i=0;
while( i< 8 )
{
if(temp&0x01) //从低到高送显示位(依取模方式而定)
{
//与普通LED主要更改点,有显示时发三个分量数据,否则发三个0
ws2812_write_byte( col_g);
ws2812_write_byte( col_r);
ws2812_write_byte( col_b);
}
else
{
//与普通LED主要更改点,有显示时发三个分量数据,否则发三个0
ws2812_write_byte( 0x00);
ws2812_write_byte( 0x00);
ws2812_write_byte( 0x00);
}
i++;
temp = temp >>1; //下一位
}
temp = dat_word1[j]; //上方16位再送第一字节(依取模方式而定)
while( i< 16 )
{
if(temp&0x01) //从低到高送显示位(依取模方式而定)
{
//与普通LED主要更改点,有显示时发三个分量数据,否则发三个0
ws2812_write_byte( col_g);
ws2812_write_byte( col_r);
ws2812_write_byte( col_b);
}
else
{
//与普通LED主要更改点,有显示时发三个分量数据,否则发三个0
ws2812_write_byte( 0x00);
ws2812_write_byte( 0x00);
ws2812_write_byte( 0x00);
}
temp = temp >>1; //下一位
i++;
}
delayUs_16Mhz(200); //延时量自行调整,当摇的速度一定时,延时越大,字越宽但能显示字数减少
j +=2; //汉字下一列
}
//发送完三个汉字后清屏
display_off();
}
/*中断服务程序*/
void intersvr0(void) interrupt 0 using 1
{
//当从右向左摇时,产生中断,KY取反变为1,此时不显示,不运行下面的语句
delayMs_16Mhz(10);
if(~P0^0)//10mS消抖
{
cont_rock ++; //判断中断次数
if(cont_rock >= 20)
cont_rock = 20;
//每个摇动来回滚珠开关会在摆幅两端分别产生下降沿中断,只提取其中一次
delayMs_16Mhz(30); //延时量改变首字显示位置,越大越靠后
if((cont_rock&0x01) == 0) //偶数时显示(或奇数次,依初值和开关方向而定)
{
display_3word();
}
else
{
display_off();
}
}
PINTF0 &= 0xFE;// HC89S003需软件清标志位INT0F
}
/**************************************************************************************
* @实现效果 将Fosc设置为16MHz,Fcpu设置为16MHz
**************************************************************************************/
void main()
{
/************************************系统初始化****************************************/
WDTCCR = 0x00; //关闭看门狗
//本例程为方便测试关闭看门狗,实际使用中,建议客户打开看门狗,详见WDT复位例程
CLKSWR = 0x51; //选择内部高频RC为系统时钟,内部高频RC 2分频,Fosc=16MHz
CLKDIV = 0x01; //Fosc 1分频得到Fcpu,Fcpu=Fosc
/**********************************相关配置初始化**************************************/
P2M1 = P2M1&0xF0|0x08; //WS2812信号 P22设置为推挽输出
P0M0 = P0M0&0xF0|0x06; //滚珠开关P00设置为带施密特上拉输入 (作为外部中断)
P00DBC = 0xFF; //滚珠开关P00端口消抖,约250uS
PITS0 = PITS0&0xFC|0x01; //外部中断0下降沿中断
EX0=1; //开外部中断
EA=1; //开总中断
cont_col = 0; //颜色索引初值
display_off();
while(1) //主程序中只检测按键
{
cont_rock = 0;
delayMs_16Mhz(1000);
if(cont_rock == 0) //检测1秒内摇摆次数,如无则颜色回初值
{
cont_col = 0;
}
else
{
//颜色索引每秒加一改变一次颜色
if(cont_col >=5) //暂用6种颜色
{
cont_col = 0;
}
else
{
cont_col ++; //改变颜色
}
//按索引赋显示颜色分量值
col_r = 0;
col_g = 0;
col_b = 0;
switch(cont_col)
{
case 0: col_r = 0x20;break;
case 1: col_g = 0x20;break;
case 2: col_b = 0x20;break;
case 3: col_r = 0x20;col_g = 0x20;break;
case 4: col_g = 0x20;col_b = 0x20;break;
case 5: col_b = 0x20;col_r = 0x20;break;
default: cont_col=0; col_r = 0x20;break;
}
}
}
}
|