没事做突然想写博客,然后发现没有刷什么有价值的题,就写个做实验的记录吧。
首先是构思的思维导图
可以看到,我用到了按键结合中断作为输入,使用定时中断来计数,同时显示使用的是oled屏幕,大小为128*64个像素点。
屏幕图片源水印淘宝店( ̄▽ ̄)"
oled管脚*7,一个3v3,一个GND,还有五个GPIO输出。
这边用的是串行通信的方法,各个管脚功能分别是
CS:OLED 片选信号。
RST(RES):硬复位 OLED。
DC:命令/数据标志(0,读写命令;1,读写数据)。
SCLK:串行时钟线。在 4 线串行模式下,D0 信号线作为串行时钟线 SCLK。
SDIN:串行数据线。在 4 线串行模式下,D1 信号线作为串行数据线 SDIN。
oled管脚:
CS~PA0
DC/RS~PA2 //这边的DC管脚在程序里面被记作了RS,都一样
RST~PA1
SCLK/D0~PB5
SDIN/D1~PB6
按键管脚*5,一个5v,一个GND,3个GPIO输入。
按键功能为
key0:开始和暂停计时
key1:重置计时
key2:计次,多人跑步的时候记下各个人情况
按键管脚:
key0~PB0
key1~PB1
key2~PB2
KEY_INIT(),我设置为上拉输入了,管脚改一下,就不多说了。
EXTI_INIT(),从按键设置可以看到,应该选中断线0,1,2,配置管脚为下降沿触发,设置NVIC中断优先级,中断服务程序先留着。
计时器初始化,这边用三号定时中断,TIM3_Int_Init(100,7199),解释一下,这个板子的时钟频率为72Mhz,我们不需要这么高的频率来做定时器中断,所以将他分频,72M除一下设置的分频值7199,得到的结果是1W,也就是现在我们的定时器中断为1Whz,我们想要计时器可以精确到0.01s,所以设置为每数100次触发一个定时器中断。然后中断服务程序就可以用来累加我们的时间了。
oled_init(),这个也就是按照之前的管脚配置做就行了,注意选择串行通信模式
先找个软件来,将中文转为16进制的点阵图,放到oled_font里面,我用了四个中文字
时间第名
,做成了四个数组,一个数组里面有32个8位的16进制数。这边用了一个OLED_DrawPoint(x,y,1)
,x和y为像素点的位置,1表示这个点要点亮,否则用0。
另外,一个字为16*16个像素点,这边写入的方式为,先(0,0)->(0,1)->(0,2)…(0,15)->(1,0)->(1,2)…(15,15)。也就是先写完一列16个像素,再换下一列。但是,我们数组中的数是8位的,也就是只保存了8个像素点的状态,所以一列要两个数来表示。
void OLED_ShowMyChinese(u8 x,u8 y,u8 n)
{
u8 temp,t,t1;//c语言要先声明变量,t,t1用来for循环,temp是取数组值
u8 y0=y; //保存列开头位置
for(t=0;t<32;t++) //遍历数组中32个数
{
temp=oled_chinese_1616[n][t]; //第n个汉字的第t个数
for(t1=0;t1<8;t1++) //遍历一个数中的八个位
{
if(temp&0x80) //查看temp最高位,看像素点状态
OLED_DrawPoint(x,y,1); //如果最高位是1,就点亮
else
OLED_DrawPoint(x,y,0); //否则暗着
temp<<=1; //左移查看下一个像素
y++; //移动到下一个像素点的物理位置
if((y-y0)==16) //这边是判断是否写完一列
{ //画完第一个8位数字后y不变回0
y=y0; //画完两个8位数字后y变回0
x++;
break;
}
}
}
}
首先想一下,时间怎么保存呢?当然是用结构体啦
struct StuTime{
u8 m,s;//八位的分钟,秒
u16 ms;//16位的毫秒
}MyTime={0,0,0};//初始化为0:0.00
写在timer.c 这个文件最合适啦。这样定时中断服务就可以直接累加时间了。
void TIM3_IRQHandler(void)
{
if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)
{
TIM_ClearITPendingBit(TIM3, TIM_IT_Update );
if(!MyFlag) //flag用来看有不有暂停计时
return;
MyTime.ms+=10; //累加毫秒
if(MyTime.ms>=1000)//累加秒
{
MyTime.ms%=1000;
MyTime.s++;
if(MyTime.s>=60)//累加分钟
{
MyTime.s%=60;
MyTime.m++;;
}
}
}
}
那么暂停的方法上面也说了,用一个flag就行了
void MyTime_GO(void)
{
MyFlag=!MyFlag;
}
void EXTI0_IRQHandler(void)
{
delay_ms(10);
MyTime_GO();
EXTI_ClearITPendingBit(EXTI_Line0);
}
另外三个按键功能也是这样的,所以主要的功能函数都在timer.c
这个文件里面了
重置计时功能
void MyTime_RST(void)
{
MyFlag=0; //先把flag设为0,暂停计时
MyTime.m=0; //再将时间全重置为0
MyTime.s=0; //这样以后呢,就不多忙活了
MyTime.ms=0;
}
然后是计次功能,显示的样式为三行,这个oled可以写四行字,这边选择下三行,第一行留给实时的时间。
这边显示的一行为第nn名: nn:nn.nn
,这个n就是到时候要替换的数字了。
void MyTime_CNT(void)
{
u8 static MyCntFlag=1;//给这个函数加个锁,防止连续触发
u8 static MyCnt=0; //打算用三行来计次这个记录我这是第几次计次了,改写哪行
u8 MyPageY;
if(!MyCntFlag) //查看有不有锁上
return ;
MyCntFlag=0; //锁上
MyPageY=(MyCnt%3+1)*16; //计算我改写哪一行,也就是y的值
//显示中文了
OLED_ShowMyChinese(0,MyPageY,2);//显示我中文字库的第二个字,就是"第"
OLED_ShowMyChinese(32,MyPageY,3);//显示"名",和下面数字和在一起就是‘第n名’了
OLED_ShowNum(16,MyPageY,MyCnt+1,2,16);
//显示分隔符
OLED_ShowChar(48,MyPageY,':',16,1);
OLED_ShowChar(80,MyPageY,':',16,1);
OLED_ShowChar(104,MyPageY,'.',16,1);
//替换数字,都是两位的数字
OLED_ShowNum(64,MyPageY,MyTime.m,2,16);//分钟
OLED_ShowNum(88,MyPageY,MyTime.s,2,16);//秒钟
OLED_ShowNum(112,MyPageY,MyTime.ms,2,16);//毫秒
MyCnt++;//记下我写过这行了,下次写下一行
MyCntFlag=1;//记得把锁打开
}
所以现在开始搞定最后一个main函数
首先,把七大姨八大叔全部叫来初始化一下,调用一个他们的init函数
然后进入永不退出的while(1)循环啦
第一行实时显示的样式为时 间: nn:nn.nn
,同上,n为要替换的数字
这边用到了一个GetTime函数,先看一下这个函数,这个函数在timer.c
里面
u32 GetTime(void)
{
return (u32)((MyTime.m<<24)+(MyTime.s<<16)+(MyTime.ms));
}
还记的我们的时间结构体吗,8位的分钟,8位的秒,16位的毫秒,加一起不就可以组成一个32位的数啦,这边就用一个32位的数返回给要查看时间的同学了,前8位为分钟,后面8位为秒,再最后16位就是毫秒了。
while(1)
{
u8 tmp;
u32 reVal=GetTime(); //从timer.c获取时间
OLED_ShowMyChinese(0,0,0); //显示‘时’
OLED_ShowMyChinese(32,0,1); //显示‘间’
OLED_ShowChar(48,0,':',16,1); //显示分隔的冒号
OLED_ShowChar(80,0,':',16,1);
OLED_ShowChar(104,0,'.',16,1);
tmp=(reVal&0xff000000)>>24;//根据前面GetTime的规则取出分钟
OLED_ShowNum(64,0,tmp,2,16);//显示分钟
tmp=(reVal&0x00ff0000)>>16;//根据前面GetTime的规则取出秒
OLED_ShowNum(88,0,tmp,2,16);//显示秒
tmp=(reVal&0x0000ffff);//根据前面GetTime的规则取出毫秒
OLED_ShowNum(112,0,tmp,2,16);//显示毫秒
OLED_Refresh_Gram();//刷新oled,注意,整个项目中不要有多个刷新调用
delay_ms(10); //否则你的屏幕会乱掉,错位
//这样看来他的刷新函数应该没有锁保护了
}
}
附上全文代码,IDE是uv4,和现在的新版本有点不兼容,但不影响阅读和移植。
https://pan.baidu.com/s/15ojkzdAZskfZgF5cXR7anA