OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
楼主: 龙之谷

菜鸟开帖,持续更新90天,顺序学习开发板大部分实验,以此帖作为一个坚持的动力

  [复制链接]

1

主题

6

帖子

0

精华

新手上路

积分
39
金钱
39
注册时间
2015-5-29
在线时间
2 小时
发表于 2015-8-1 21:58:25 | 显示全部楼层
加入队伍。。。。。。我刚看到了TFTLCD显示屏感觉不是特别懂
长路漫漫,唯剑作伴。
正点原子逻辑分析仪DL16劲爆上市
回复 支持 反对

使用道具 举报

72

主题

2711

帖子

2

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
3505
金钱
3505
注册时间
2014-8-4
在线时间
696 小时
 楼主| 发表于 2015-8-1 22:36:10 | 显示全部楼层
第一一天  2015年08月01日  周六     例程:通用定时器、PWM配置过程汇总

一、通用定时器配置过程

1.时钟使能



2.设定计数器自动重装值


3.预分频器



4.允许更新中断



5.使能定时器


6.中断分组设置
MY_NVIC_Init();

二、PWM配置过程(ARR、PSC寄存器见上)

1.设置PWM模式寄存器


2.使能输出
  2.1单个通道



   2.2使能对应总开关



3.控制占空比



【注】4.如果是高级定时器,在以上通用定时器配置基础上,还需配置:刹车和死区寄存器(TIMx_BDTR



三、配置函数



四、相关链接(最后四个是有关SPWM的链接)
【1】http://www.openedv.com/posts/list/7235.htm
【2】http://www.openedv.com/posts/list/13166.htm
【3】http://www.openedv.com/posts/list/140.htm
【4】http://www.openedv.com/posts/list/33888.htm
【5】http://www.openedv.com/posts/list/11417.htm
【6】http://www.openedv.com/posts/list/6487.htm
【7】http://wenku.baidu.com/link?url=8GroWLOaTURk0VGqCTpkxXRycXFqeTfwiR-AwA_hE7BBzsZbNqG2OgzmqVApqvAeWgj17vOmHtKlJLl3DXAhQivKtkTZititDDMPqSv-PQa

【8】http://www.openedv.com/posts/list/56082.htm
【9】http://www.openedv.com/posts/list/17645.htm
【10】http://www.openedv.com/posts/list/8017.htm
【11】http://www.docin.com/p-913621558.html
以我资质之鲁钝,当尽平心静气、循序渐进、稳扎稳打之力。
回复 支持 反对

使用道具 举报

72

主题

2711

帖子

2

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
3505
金钱
3505
注册时间
2014-8-4
在线时间
696 小时
 楼主| 发表于 2015-8-1 22:38:27 | 显示全部楼层
回复【100楼】坏男孩:
---------------------------------
可别把我当榜样喽,还是一菜鸟。

一起努力,共同进步......
以我资质之鲁钝,当尽平心静气、循序渐进、稳扎稳打之力。
回复 支持 反对

使用道具 举报

72

主题

2711

帖子

2

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
3505
金钱
3505
注册时间
2014-8-4
在线时间
696 小时
 楼主| 发表于 2015-8-1 22:39:47 | 显示全部楼层
回复【101楼】大鱼:
---------------------------------
如果有问题欢迎交流讨论

欢迎加入......
以我资质之鲁钝,当尽平心静气、循序渐进、稳扎稳打之力。
回复 支持 反对

使用道具 举报

72

主题

2711

帖子

2

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
3505
金钱
3505
注册时间
2014-8-4
在线时间
696 小时
 楼主| 发表于 2015-8-2 16:03:45 | 显示全部楼层
第一二天  2015年08月02日  周日     例程:输入捕获实验



1.输入捕获模式可以用来测量脉冲宽度或者测量频率。
2.输入捕获原理示意图





3.通俗的说,捕获过程就是,设置相应捕获模式,第一次触发捕获时记下时间1,转变捕获模式,第二次触发捕获时记下时间2,两次时间值之差就是此次捕获电平的持续时间。而开发指南对这个过程进行了轻微处理,就是把第一次捕获后的时间1归零,此时开始计时,第二次捕获时经历时长即为捕获电平的持续时间。

4.原子哥定义了变量,进行类似寄存器处理,程序如下(个人对注释有更改)
[mw_shl_code=c,true]uchar TIM5CH1_CAPTURE_STA = 0; //输入捕获状态 uint TIM5CH1_CAPTURE_VAL = 0; //输入捕获值 void TIM5_IRQHandler(void) { uint tsr = 0; tsr = TIM5->SR; if((TIM5CH1_CAPTURE_STA & 0X80) == 0) //还未成功捕获 { if(tsr & 0x01) //溢出 ② { if(TIM5CH1_CAPTURE_STA & 0X40) //已经捕获到高电平 { if((TIM5CH1_CAPTURE_STA & 0X3F) == 0X3F) //高电平太长了 { TIM5CH1_CAPTURE_STA |= 0X80; //强制标记成功捕获一次 TIM5CH1_CAPTURE_VAL = 0XFFFFFFFF; } else { TIM5CH1_CAPTURE_STA++; } } } if(tsr & 0x02) //捕获1发生捕获事件 ③ { if(TIM5CH1_CAPTURE_STA & 0X40) //捕获到一个下降沿 { TIM5CH1_CAPTURE_STA |= 0X80; //标记成功捕获到一次高电平 TIM5CH1_CAPTURE_VAL = TIM5->CCR1; //获取当前捕获值 TIM5->CCER &= ~(1 << 1); //设置为上升沿捕获 } else //还未开始,第一次捕获上升沿 ① { TIM5CH1_CAPTURE_STA = 0; //清空 TIM5CH1_CAPTURE_VAL = 0; TIM5CH1_CAPTURE_STA |= 0X40; //标记捕获到了上升沿 TIM5->CR1 &= ~(1 << 0); //除能定时器5 TIM5->CNT = 0; //计数器清空 TIM5->CCER |= 1 << 1; //设置为下降沿捕获 TIM5->CR1 |= 0X01; //使能定时器5 } } } TIM5->SR = 0; }[/mw_shl_code]
注意一下程序中后来添加的①②③,捕获的处理过程是从①到③的,②并不是一定执行,它的执行需要满足一定条件,即发生了溢出。
原子哥的自己定义的这个类似于寄存器的变量,对其各位的判断过程是从高位到低位的,与实际捕获过程基本是相反的,所以我们理解的时候会有一点不适应,但就程序本身来说,开发指南的程序个人感觉非常缜密与紧凑。

5.在3中说道开发指南对第一次计时进行了清零,这个操作并不是必须的,现在我们来还原一个不被清零的过程,借鉴于原子哥自定义变量处理过程,在此自定义一个结构,按照捕获过程来进行顺序处理,这样的处理过程简单的同时也比较符合我们朴素的逻辑习惯。
其一,定义结构体
[mw_shl_code=c,true]struct CAPTURE { uchar flag; //捕获过程进度标志 uchar num; //溢出次数 long long value1; //第一次捕获值 long long value2; //第二次捕获值 };[/mw_shl_code]
其二,初始化结构体
[mw_shl_code=c,true]struct CAPTURE mycap; //定义 void Struct_Init(void) //初始化结构 { mycap.flag = 0; mycap.num = 0; mycap.value1 = 0; mycap.value2 = 0; }[/mw_shl_code]
其三,定时器5中断服务函数
[mw_shl_code=c,true]void TIM5_IRQHandler(void) { uint tsr = 0; tsr = TIM5->SR; if(mycap.flag != 2) //没有捕获完成 { if((tsr & 0x02) && (mycap.flag == 0)) //第一次触发捕获 { mycap.flag = 1; //第一次成功捕获高电平 mycap.value1 = TIM5->CCR1; //获取当前捕获值 TIM5->CCER |= 1 << 1; //设置为下降沿捕获 } else if((tsr & 0x02) && (mycap.flag == 1)) //第二次触发捕获 { mycap.flag = 2; //第二次成功捕获低电平,捕获完成 mycap.value2 = TIM5->CCR1; //获取当前捕获值 TIM5->CCER &= ~(1 << 1); //重新设置为上升沿捕获 } if(tsr & 0x01) //溢出 { mycap.num++; if(mycap.num == 255) //捕获事件过长 { mycap.flag = 2; //强制捕获完成 mycap.value2 = 0xffffffff; //强制赋最大值 } } } TIM5->SR = 0; }[/mw_shl_code]
其四,主函数通过串口打印显示
[mw_shl_code=c,true] Struct_Init(); while(1) { delay_ms(10); LED0_PWM_VAL++; if(LED0_PWM_VAL == 300) { LED0_PWM_VAL = 0; } if(mycap.flag == 2) { temp = mycap.num; temp *= 0xffffffff; temp += mycap.value2; temp -= mycap.value1; printf("HIGH:%lld us\r\n",temp); printf("VAL1:%lld us\r\n",mycap.value1); printf("VAL2:%lld us\r\n",mycap.value2); printf("NUM :%o times\r\n",mycap.num); Struct_Init(); } }[/mw_shl_code]
最后,捕获实验串口打印显示






概念区分
1.中断和事件(截图自STM32F4XX中文参考手册)

图一:


图二:


图三:



总结:两者本是同根生,他们的产生源可以是一样的。
中断的两个必须,其一,必须CPU参与;其二,必须要有中断服务函数。
事件不一定需要CPU参与处理,靠脉冲发生器产生一个脉冲,进而由硬件自动完成这个事件产生的结果,比如触发DMA、AD采样等。事件机制提供了一个可以完全由硬件自动完成的触发到产生结果的通道,不需要软件的参与,降低了CPU的负荷,节省了中断资源,提供了响应速度(硬件总快于软件),是利用硬件来提升CPU芯片处理事件能力的一个有效方法。

2.更新中断和触发中断
更新中断一般是指计数器上溢/下溢时产生的中断,此时完成两个动作,其一,置位了更新中断标志位;其二,重新装载初始化定时的设定值。这两个动作都有单片机自动完成,即更新中断只是用于单片机(按照我们的配置进行内部)处理,我们不进行直接参与。
触发中断一般是指外部触发,比如ETR(external triger)。

3.输入捕获和输出比较
输入捕获:具有此功能的引脚,配置相应定时器,当此引脚触发捕获进入中断,此时读出定时器的值,继续运行,等待下次触发,再读取一次定时器的值,两次触发之间的时间差就是捕获的脉宽。
输出比较:在比较寄存器先存放预定值,当定时器按照配置向上/向下计数并进行比较,满足比较条件时,输出电平发生跳变,如PWM。

4.有效电平
有效电平就是PWM匹配时的输出电平。CCxP是用来控制极性的,默认为0,如果置位该位,则为低电平有效。



【1】http://www.openedv.com/posts/list/2495.htm
【2】http://www.openedv.com/posts/list/2543.htm
【3】http://www.openedv.com/posts/list/12602.htm
【4】http://www.openedv.com/posts/list/19486.htm
【5】http://blog.163.com/iceberg_gao/blog/static/186680516201341055224422/
【6】http://www.ichanging.org/stm32_tim_led.html
【7】http://www.openedv.com/posts/list/140.htm
【8】http://www.openedv.com/posts/list/685.htm
【9】http://www.openedv.com/posts/list/22323.htm;jsessionid=25435111D053937C755E3200F62F9355
【10】http://blog.csdn.net/jdh99/article/details/23224041
【11】http://blog.csdn.net/jdh99/article/details/23252719
【12】http://www.21ic.com/app/control/201111/97133_2.htm
注:其中10~12为DMA与捕获模式配合使用相关资料,尚未进行实际编程学习
以我资质之鲁钝,当尽平心静气、循序渐进、稳扎稳打之力。
回复 支持 反对

使用道具 举报

72

主题

2711

帖子

2

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
3505
金钱
3505
注册时间
2014-8-4
在线时间
696 小时
 楼主| 发表于 2015-8-2 16:06:51 | 显示全部楼层
吃饭去喽,周日的早餐午餐一起啦,看极限挑战的时候来个夜宵当晚餐,突然发现一天吃够两顿饭蛮难的
以我资质之鲁钝,当尽平心静气、循序渐进、稳扎稳打之力。
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165309
金钱
165309
注册时间
2010-12-1
在线时间
2108 小时
发表于 2015-8-2 23:10:12 | 显示全部楼层
回复【106楼】龙之谷:
---------------------------------
顶...
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

4

主题

29

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
438
金钱
438
注册时间
2013-7-16
在线时间
71 小时
发表于 2015-8-3 10:28:33 | 显示全部楼层
期待中。。。。。。
回复 支持 反对

使用道具 举报

1

主题

7

帖子

0

精华

新手上路

积分
31
金钱
31
注册时间
2015-8-3
在线时间
0 小时
发表于 2015-8-3 17:08:41 | 显示全部楼层
刚入坑的新手求问,pwm实验如果要把led的输出改成ds1的话,需要修改那些地方?最好两种方法(库函数,寄存器)都给出解决办法。
逗逼在某些人眼里,即把两个字倒过来读的伺候。
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165309
金钱
165309
注册时间
2010-12-1
在线时间
2108 小时
发表于 2015-8-3 22:39:38 | 显示全部楼层
等更新了。。。
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

72

主题

2711

帖子

2

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
3505
金钱
3505
注册时间
2014-8-4
在线时间
696 小时
 楼主| 发表于 2015-8-3 23:21:39 | 显示全部楼层
回复【110楼】正点原子:
---------------------------------
求助:

正在粗略整理触摸按键,感觉u8 TPAD_Scan(u8 mode)函数有点问题

我测试的时候:1.不论mode为1还是为0,DS1都闪烁不停;2.keyen=3;这条语句在此处感觉不是很恰当,应该起不到3次检测的作用啊。
以我资质之鲁钝,当尽平心静气、循序渐进、稳扎稳打之力。
回复 支持 反对

使用道具 举报

72

主题

2711

帖子

2

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
3505
金钱
3505
注册时间
2014-8-4
在线时间
696 小时
 楼主| 发表于 2015-8-3 23:23:24 | 显示全部楼层
为节省原子哥时间,此处贴上函数源码、

[mw_shl_code=c,true]//扫描触摸按键 //mode:0,不支持连续触发(按下一次必须松开才能按下一次);1,支持连续触发(可以一直按下) //返回值:0,没有按下;1,有按下; #define TPAD_GATE_VAL 100 //触摸的门限值,也就是必须大于tpad_default_val+TPAD_GATE_VAL,才认为是有效触摸. u8 TPAD_Scan(u8 mode) { static u8 keyen=0; //0,可以开始检测;>0,还不能开始检测 u8 res=0; u8 sample=3; //默认采样次数为3次 u16 rval; if(mode) { sample=6; //支持连按的时候,设置采样次数为6次 keyen=0; //支持连按 } rval=TPAD_Get_MaxVal(sample); if(rval>(tpad_default_val+TPAD_GATE_VAL)&&rval<(10*tpad_default_val))//大于tpad_default_val+TPAD_GATE_VAL,且小于10倍tpad_default_val,则有效 { if(keyen==0)res=1; //keyen==0,有效 //printf("r:%d\r\n",rval); keyen=3; //至少要再过3次之后才能按键有效 } if(keyen)keyen--; return res; } [/mw_shl_code]

以我资质之鲁钝,当尽平心静气、循序渐进、稳扎稳打之力。
回复 支持 反对

使用道具 举报

72

主题

2711

帖子

2

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
3505
金钱
3505
注册时间
2014-8-4
在线时间
696 小时
 楼主| 发表于 2015-8-4 00:15:12 | 显示全部楼层
第一三天  2015年08月03日  周一     例程:触摸按键实验

1.触摸按键原理





2.实验过程



3.空载充电时间函数--这段函数的气泡法排序及滤除偏差数据的过程很值得实际使用
[mw_shl_code=c,true]//初始化触摸按键 //获得空载的时候触摸按键的取值. //psc:分频系数,越小,灵敏度越高. //返回值:0,初始化成功;1,初始化失败 u8 TPAD_Init(u8 psc) { u16 buf[10]; u16 temp; u8 j,i; TIM2_CH1_Cap_Init(TPAD_ARR_MAX_VAL,psc-1);//设置分频系数 for(i=0;i<10;i++)//连续读取10次 { buf=TPAD_Get_Val(); delay_ms(10); } for(i=0;i<9;i++)//排序 { for(j=i+1;j<10;j++) { if(buf>buf[j])//升序排列 { temp=buf; buf=buf[j]; buf[j]=temp; } } } temp=0; for(i=2;i<8;i++)temp+=buf;//取中间的8个数据进行平均 tpad_default_val=temp/6; printf("tpad_default_val:%d\r\n",tpad_default_val); if(tpad_default_val>TPAD_ARR_MAX_VAL/2)return 1;//初始化遇到超过TPAD_ARR_MAX_VAL/2的数值,不正常! return 0; }[/mw_shl_code]
4.扫描触摸按键--开发指南源程序
[mw_shl_code=c,true]//扫描触摸按键 //mode:0,不支持连续触发(按下一次必须松开才能按下一次);1,支持连续触发(可以一直按下) //返回值:0,没有按下;1,有按下; #define TPAD_GATE_VAL 100 //触摸的门限值,也就是必须大于tpad_default_val+TPAD_GATE_VAL,才认为是有效触摸. u8 TPAD_Scan(u8 mode) { static u8 keyen=0; //0,可以开始检测;>0,还不能开始检测 u8 res=0; u8 sample=3; //默认采样次数为3次 u16 rval; if(mode) { sample=6; //支持连按的时候,设置采样次数为6次 keyen=0; //支持连按 } rval=TPAD_Get_MaxVal(sample); if(rval>(tpad_default_val+TPAD_GATE_VAL)&&rval<(10*tpad_default_val))//大于tpad_default_val+TPAD_GATE_VAL,且小于10倍tpad_default_val,则有效 { if(keyen==0)res=1; //keyen==0,有效 //printf("r:%d\r\n",rval); keyen=3; //至少要再过3次之后才能按键有效 printf("keyen333:%d\r\n", keyen); } if(keyen)keyen--; printf("keyen:%d\r\n", keyen); return res; } [/mw_shl_code]
此段程序在测试中的现象
其一,无论mode取值为0或1,DS1小灯都是不停闪烁,没有明显区别出来是否支持连按;
其二,keyen=3;这条语句在此处感觉有点别扭。当mode=0,也就是不支持连按的时候,假如连按,第一次符合那个长的if判断句,按理论来说能够返回一次res=1;此时keyen=3,只有放下按键后keyen自减三次才有机会再次按下按键触发下一次if(keyen==0)的判断,但实际测试时,连按按键也触发了if(keyen==0)这条判断-----起初百思不得其解,后来猜测虽然长按按键但有时候按键采集的数据可能没有达到长的if判断句的要求,所以,误判为没有按下。为进一步测试,将keyen=3;这条语句换成keyen=200;果然测试结果如下图,此时按下按键,指示灯只是变化一次,但由于keyen为200,所以松下按键再次按下时中间需要一个小的时间间隔供keyen自减到0,恢复初始状态。



经过以上测试,将程序调整为
[mw_shl_code=c,true]u8 TPAD_Scan(u8 mode) { static u8 keyen = 0; u8 res = 0, sample = 3; //默认采样3次 u16 rval; static u8 flag = 0; //按下标志位-----新添加 if(mode) { sample = 6; //支持连按的时候,采样次数为6次 keyen = 0; flag = 0; //清除按下标志位,支持连按,即一次长时间按下识别多次 } rval = TPAD_Get_MaxVal(sample); if(rval > (tpad_default_val + TPAD_GATE_VAL) && rval < (10 * tpad_default_val)) //大于tpad_default_val+TPAD_GATE_VAL,且小于10倍tpad_default_val,则有效 { if(keyen == 0 && flag == 0) { res = 1; flag = 1; } keyen = 5; //至少要再过5次之后才能按键有效 ,滤除误判 printf("rval:%d\r\n", rval); } else if(rval <= (tpad_default_val + TPAD_GATE_VAL)) { flag = 0; } if(keyen) { keyen--; } return res; }[/mw_shl_code]
此时,若mode=0,不支持连按,则需检测到5次未按下才能再次识别下一次按键按下,提升滤除误判效果,而又无需两次按下间隔时间过长。
以我资质之鲁钝,当尽平心静气、循序渐进、稳扎稳打之力。
回复 支持 反对

使用道具 举报

72

主题

2711

帖子

2

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
3505
金钱
3505
注册时间
2014-8-4
在线时间
696 小时
 楼主| 发表于 2015-8-4 00:17:39 | 显示全部楼层
冒着雨回到宿舍,停电,爬到顶楼,饿了,顺着楼梯下楼,吃完饭接着爬楼梯,刚开门,来电了

这是一个真实的故事
以我资质之鲁钝,当尽平心静气、循序渐进、稳扎稳打之力。
回复 支持 反对

使用道具 举报

72

主题

2711

帖子

2

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
3505
金钱
3505
注册时间
2014-8-4
在线时间
696 小时
 楼主| 发表于 2015-8-5 00:01:57 | 显示全部楼层
第一四天  2015年08月04日  周二     例程:OLED显示实验(未实际下载测试)

一、基础知识
1.OLED,即有机发光二极管(Organic Light—Emitting Diode),又称为有机电激光显示(Organic Electroluminesence Display,OLED).
2.8080并行接口,发明者是INTEL,被广泛应用于液晶显示屏。包括以下信号线


3.8080并口读/写过程为:先根据要写入/读出的数据类型,设置DC为高(数据)/低(命令),然后拉低片选,选中SSD1306,接着根据是读数据还是写数据设置RD/WR为低,然后:
在RD的上升沿,使数据锁存到数据线(D[7:0])上;
在WR的上升沿,使数据写入到SSD1305里面。
4.假读命令(Dummy Read),有时候再8080方式下读数据操作,需要一个假读命令,以使得微控制器的操作频率和显存的操作频率相匹配,这里的假读就是第一个读到的字节丢弃不要,从第二个开始才是我们需要的数据。

二、程序学习
1.拼凑法--非连续端口统一管理
[mw_shl_code=c,true]//通过拼凑的方法向OLED输出一个8位数据 //data:要输出的数据 void OLED_Data_Out(u8 data) { u16 dat=data&0X0F; GPIOC->ODR&=~(0XF<<6); //清空6~9 GPIOC->ODR|=dat<<6; //D[3:0]-->C[9:6] PCout(11)=(data>>4)&0X01; //D4 PBout(6)=(data>>5)&0X01; //D5 PEout(5)=(data>>6)&0X01; //D6 PEout(6)=(data>>7)&0X01; //D7 } [/mw_shl_code]
2.向SSD1305写入一个字节--如上的8080读写过程
[mw_shl_code=c,true]//向SSD1306写入一个字节。 //dat:要写入的数据/命令 //cmd:数据/命令标志 0,表示命令;1,表示数据; void OLED_WR_Byte(u8 dat,u8 cmd) { OLED_Data_Out(dat); OLED_RS=cmd; OLED_CS=0; OLED_WR=0; OLED_WR=1; OLED_CS=1; OLED_RS=1; } [/mw_shl_code]
3.SPI写数据



4.进行完写函数,可以发现与OLED沟通最大的一条坎已经跨过了,接下来的操作可以分为两个部分:其一,通过写函数控制OLED寄存器,实现我们需要的配置;其二,纯软件一步步实现算法,通过写函数显示到屏幕上,完成显示。

oled(OLED实验寄存器版本例程oled.c源码,留此备查).c

7.84 KB, 下载次数: 68

以我资质之鲁钝,当尽平心静气、循序渐进、稳扎稳打之力。
回复 支持 反对

使用道具 举报

42

主题

358

帖子

0

精华

高级会员

Rank: 4

积分
889
金钱
889
注册时间
2014-8-16
在线时间
193 小时
发表于 2015-8-5 21:54:26 | 显示全部楼层
我草 我怎么一回复 内容全出来了 我还以为你偷懒到1号没更新了
回复 支持 反对

使用道具 举报

72

主题

2711

帖子

2

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
3505
金钱
3505
注册时间
2014-8-4
在线时间
696 小时
 楼主| 发表于 2015-8-5 22:09:40 | 显示全部楼层
回复【116楼】Theone:
---------------------------------
键盘上有个按键叫  F5,哈哈
以我资质之鲁钝,当尽平心静气、循序渐进、稳扎稳打之力。
回复 支持 反对

使用道具 举报

72

主题

2711

帖子

2

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
3505
金钱
3505
注册时间
2014-8-4
在线时间
696 小时
 楼主| 发表于 2015-8-5 22:43:21 | 显示全部楼层
第一五天  2015年08月05日  周三     例程:TFTLCD显示实验

前言:由于本例程知识点以及难度对个人而言陡然增大,故采取零碎学习的方式,在进行后续例程的过程中,慢慢进行总结,逐步掌握。

1.TFT-LCD即薄膜晶体管液晶显示器,英文全程:Thin Film Transistor-Liquid Crystal Display。它在每一个像素上都有一个薄膜晶体管(TFT),可有效克服非选通时的串扰,使显示液晶屏的静态特性与扫描线数无关,大大提高了图像质量。也被称为真彩液晶显示器。
2.主要特点



3.TFTLCD模块使用流程



4.FSMC,即灵活的静态存储控制器,能够与同步或异步存储器和16位PC存储器卡连接,STM32F4的FSMC接口支持包括SRAM、NAND FLASH、NOR FLASH和PSRAM等存储器。


附件为开发指南使用FSMC的STM32F4与不使用FSMC的STM32MINI寄存器例程,上传一下便于日后对比查找

ALIENTEK TFTLCD显示实验寄存器版例程源码.rar

996.33 KB, 下载次数: 728

以我资质之鲁钝,当尽平心静气、循序渐进、稳扎稳打之力。
回复 支持 反对

使用道具 举报

3

主题

41

帖子

1

精华

中级会员

Rank: 3Rank: 3

积分
224
金钱
224
注册时间
2014-9-2
在线时间
0 小时
发表于 2015-8-5 23:38:20 | 显示全部楼层
这几天一直关注你的贴,每次发现直到99楼,怎么没有更新?以为你放弃了。没想到是我傻x了,原来你都换页了!!!!!!!!加油楼主
趁着年轻,追逐自己所爱的----单片机&&足球!
回复 支持 反对

使用道具 举报

72

主题

2711

帖子

2

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
3505
金钱
3505
注册时间
2014-8-4
在线时间
696 小时
 楼主| 发表于 2015-8-6 22:44:31 | 显示全部楼层
回复【119楼】非洲小男孩:
---------------------------------
坚持确实不是很容易...
以我资质之鲁钝,当尽平心静气、循序渐进、稳扎稳打之力。
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165309
金钱
165309
注册时间
2010-12-1
在线时间
2108 小时
发表于 2015-8-6 23:18:24 | 显示全部楼层
回复【120楼】龙之谷:
---------------------------------
顶你,确实不容易。
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

72

主题

2711

帖子

2

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
3505
金钱
3505
注册时间
2014-8-4
在线时间
696 小时
 楼主| 发表于 2015-8-6 23:41:32 | 显示全部楼层
第一六天  2015年08月06日  周四     例程:USMART调试组件实验

一、USMART简介



二、USMART移植过程简介

1.添加USMART文件夹到项目中
2.在主函数所在.C文件包含#include  "usmart.h"
3.在usmart_config.c文件中包含#include  "delay.h"   #include  "sys.h" 以及需要调试函数所在头文件
4.在usmart_config.c文件中添加需要调试函数,添加格式为:(void*)+函数名+逗号+“函数定义整体”+逗号,如
调试延时函数void delay_ms(u16 nms)则添加格式为   (void*)delay_ms,"void delay_ms(u16 nms)",  
5.默认提供STM32F4的TIM4中断初始化设置代码,在usmart.h里面设置USMART_ENTIMX_SCAN为1
6.在主函数程序中对usmart初始化,usmart_dev.init(84)

三、USMART六个文件

1.readme.txt-----说明文件,不参与编译
2.usmart.h-----头文件,含有几个用户配置宏定义,配置usmart功能及总参数长度、是否使能定时器扫描、是否使用读写函数。
3.usmart.c-----负责与外部交互
4.usmart_str.h-----头文件
5.usmart_str.c-----主要负责命令和参数解析
6.usmart_config.c-----主要由用户添加需要由usmart管理的函数

四、系统命令

1.list--用于打印所有usmart可调用函数
2.id--获取各个函数的入口地址
3.help/?-----打印usmart使用的帮助信息
4.hex/dec-----不带参数时,分别用于设置串口显示数据格式;带参数时,对参数执行进制转换
5.runtime-----用于函数执行时间统计功能的开启与关闭,如runtime 1,开启函数执行时间统计功能;runtime 0,关闭
6.【注】一般函数可如在mian函数中一样直接调用(函数无需最后分号),带有函数参数的函数调用,需先通过id命令得到函数参数入口地址,然后用此入口地址替换函数参数进行函数调用即可。

五、USMART文件夹中usmart.cusmart_str.c基础分析
1.usmart.c文件
u8 *sys_cmd_tab[];-----系统命令数组
u8 usmart_sys_cmd_exe(u8 *str)-----对匹配的系统命令进行处理
void usmart_reset_runtime(void)-----复位runtime,即复位定时器TIM4的CNT
u32 usmart_get_runtime(void)-----获取runtime,即获取TIM4的CNT
void TIM4_IRQHandler(void)-----定时器4中断服务程序
void Timer4_Init(u16 arr,u16 psc)-----初始化定时器TIM4
void usmart_init(u8 sysclk)-----调用定时器初始化函数进行设置
u8 usmart_cmd_rec(u8*str)-----从str中获取函数名、id、参数信息 
void usmart_exe(void)-----usmart执行函数,在串口打印执行情况
void usmart_scan(void)-----扫描函数,扫描串口数据状态,据需调用执行函数
u32 read_addr(u32 addr)-----读取指定地址值
void write_addr(u32 addr,u32 val)-----指定地址写入值

2.usmart_str.h
u8 usmart_strcmp(u8 *str1,u8 *str2)-----比较字符串
void usmart_strcopy(u8*str1,u8 *str2)-----把str1中内容复制到str2
u8 usmart_strlen(u8*str)-----获得字符串长度(字节)
u32 usmart_pow(u8 m,u8 n)-----m的n次方
u8 usmart_str2num(u8*str,u32 *res)-----字符串转为数字,将str字符串转换为数字后存入*res地址处
u8 usmart_get_cmdname(u8*str,u8*cmdname,u8 *nlen,u8 maxlen)-----获取指令名
u8 usmart_search_nextc(u8* str)-----获取下一个字符
u8 usmart_get_fname(u8*str,u8*fname,u8 *pnum,u8 *rval)-----获取函数参数名等信息
u8 usmart_get_aparm(u8 *str,u8 *fparm,u8 *ptype)-----得到一个函数的参数
u8 usmart_get_parmpos(u8 num)-----得到指定参数的起始地址
u8 usmart_get_fparam(u8*str,u8 *parn)-----从str中获取函数参数
以我资质之鲁钝,当尽平心静气、循序渐进、稳扎稳打之力。
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165309
金钱
165309
注册时间
2010-12-1
在线时间
2108 小时
发表于 2015-8-7 01:19:36 | 显示全部楼层
回复【122楼】龙之谷:
---------------------------------
顶。。。。
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165309
金钱
165309
注册时间
2010-12-1
在线时间
2108 小时
发表于 2015-8-7 13:07:58 | 显示全部楼层
回复【122楼】龙之谷:
---------------------------------
分析的不错啊,呵呵。
今天讲RTC了?
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

0

主题

1

帖子

0

精华

新手入门

积分
22
金钱
22
注册时间
2013-11-28
在线时间
0 小时
发表于 2015-8-7 14:52:47 | 显示全部楼层
顶你。。。。。。。。。。。。。。。。
回复 支持 反对

使用道具 举报

72

主题

2711

帖子

2

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
3505
金钱
3505
注册时间
2014-8-4
在线时间
696 小时
 楼主| 发表于 2015-8-7 19:07:36 | 显示全部楼层
回复【124楼】正点原子:
---------------------------------
嗯,今天RTC

得想法换个花样了,老一个样不仅是对毅力的考验,也是对内心的“煎熬”
以我资质之鲁钝,当尽平心静气、循序渐进、稳扎稳打之力。
回复 支持 反对

使用道具 举报

72

主题

2711

帖子

2

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
3505
金钱
3505
注册时间
2014-8-4
在线时间
696 小时
 楼主| 发表于 2015-8-7 19:07:55 | 显示全部楼层
回复【125楼】youyyz:
---------------------------------
我也顶你,哈哈
以我资质之鲁钝,当尽平心静气、循序渐进、稳扎稳打之力。
回复 支持 反对

使用道具 举报

72

主题

2711

帖子

2

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
3505
金钱
3505
注册时间
2014-8-4
在线时间
696 小时
 楼主| 发表于 2015-8-7 19:48:40 | 显示全部楼层
第一七天  2015年08月07日  周五     例程:RTC实时时钟实验

一、基础知识

1.STM32F4的RTC是一个独立的BCD定时器/计数器。

2.RTC模块和时钟配置是在后备区域,即从系统复位或从待机模式唤醒后RTC的设置和时间维持不变,只要后备区域供电正常,RTC可以一直运行。但是系统复位后,会自动禁止访问后备寄存器和RTC,以防止对后备区域BKP的意外写操作。所以在设置时间之前,先要取消备份区域(BKP)写保护。


3.RTC备份区域:RTC_BKPxP,该寄存器组总共有20个,每个寄存器是32位,可以存储80个字节的用户数据,这些寄存器在备份区域实现,可在VDD电源关闭时通过VBAT保持上电状态。

我们可以用BKP来存储一些重要数据,相当于EEPROM,但它需要电池来维持数据。
复位后,对RTC和RTC备份寄存器地写访问被禁止,执行一下操作可以使能:首先,通过设置寄存器RCC_APB1ENR的PWREN位来打开电源接口时钟;然后,电源控制寄存器(PWR_CR)的DBP位来使能对RTC及其备份寄存器的访问。

二、知识点学习

1.备份区域控制
其一,备份区域使能RCC->APB1ENR |= 1 << 28;     PWR->CR |= 1 << 8;
其二,写入后备区域
[mw_shl_code=c,true]//RTC写入后备区域SRAM //BKPx:后备区寄存器编号,范围:0~19 //data:要写入的数据,32位长度 void RTC_Write_BKR(u32 BKRx,u32 data) { u32 temp=0; temp=RTC_BASE+0x50+BKRx*4; (*(u32*)temp)=data; }[/mw_shl_code]
其三,读取后备区域
[mw_shl_code=c,true]//RTC读取后备区域SRAM //BKPx:后备区寄存器编号,范围:0~19 //返回值:读取到的数据 u32 RTC_Read_BKR(u32 BKRx) { u32 temp=0; temp=RTC_BASE+0x50+BKRx*4; return (*(u32*)temp); //返回读取到的值 }[/mw_shl_code]

2.十进制与BCD互相转换
其一,十进制转换为BDC码
[mw_shl_code=c,true]//十进制转换为BCD码 //val:要转换的十进制数 //返回值:BCD码 u8 RTC_DEC2BCD(u8 val) { u8 bcdhigh = 0; while(val>=10) { bcdhigh++; val-=10; } return ((u8)(bcdhigh<<4)|val); }[/mw_shl_code]
其二,BCD码转换为十进制
[mw_shl_code=c,true]//BCD码转换为十进制数据 //val:要转换的BCD码 //返回值:十进制数据 u8 RTC_BCD2DEC(u8 val) { u8 temp=0; temp=(val>>4)*10; return (temp+(val&0X0F)); }[/mw_shl_code]

3.通过函数指针参数返回所需数据
[mw_shl_code=c,true]void RTC_Get_Time(u8 *hour,u8 *min,u8 *sec,u8 *ampm) { u32 temp=0; while(RTC_Wait_Synchro()); //等待同步 temp=RTC->TR; *hour=RTC_BCD2DEC((temp>>16)&0X3F); *min=RTC_BCD2DEC((temp>>8)&0X7F); *sec=RTC_BCD2DEC(temp&0X7F); *ampm=temp>>22; }[/mw_shl_code]
主函数中调用方式
 u8 hour,min,sec,ampm;     //定义所需变量
  RTC_Get_Time(&hour,&min,&sec,&ampm);     //调用函数,返回时间数据
  sprintf((char*)tbuf,"Time:%02d:%02d:%02d",hour,min,sec);     //显示
当然,我们也可以直接使用指针调用,但过程可能繁琐一些
  u8 hour,min,sec,ampm;     //定义所需变量
  u8 *Phour = &hour, *Pmin = &hour, *Psec = &sec, *Pampm = ampm;     //定义指针

  RTC_Get_Time(Phour,Pmin,Psec,Pampm);     //调用函数,返回时间数据
  sprintf((char*)tbuf,"Time:%02d:%02d:%02d",*Phour,*Pmin,*Psec);     //显示
假如直接使用指针时,定义四个整型变量,只定义指针可以吗,如u8 *Phour = NULL, *Pmin = NULL, *Psec = NULL, *Pampm = NULL;答案是不可以,这样虽然定义指针时进行了初始化,避免野指针的情况,但四个指针都是空指针,此时在液晶屏上打印出来的数据都是16,但具体为什么是这个数还不清楚【question】。

以我资质之鲁钝,当尽平心静气、循序渐进、稳扎稳打之力。
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165309
金钱
165309
注册时间
2010-12-1
在线时间
2108 小时
发表于 2015-8-8 00:45:55 | 显示全部楼层
回复【128楼】龙之谷:
---------------------------------
不错啊,呵呵,深夜来顶你
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

72

主题

2711

帖子

2

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
3505
金钱
3505
注册时间
2014-8-4
在线时间
696 小时
 楼主| 发表于 2015-8-8 23:22:21 | 显示全部楼层
第一八天  2015年08月08日  周六     例程:随机数实验

1.随机数发生器(RNG),是一个以连续模拟噪声为基础的随机数发生器,在主机读数时提供一个32位的随机数。
2.随机数发生器框图(虽然贴这张图没什么意义,但贴上自我感觉本文立马上个档次,也能撑一下今天的界面)


3.函数总结
其一,初始化函数。完成一般初始化操作-----初始化时钟,使能RNG,等待就绪
[mw_shl_code=c,true]//初始化RNG //返回值:0,成功;1,失败 u8 RNG_Init(void) { u16 retry=0; RCC->AHB2ENR=1<<6; //开启RNG时钟,来自PLL48CLK RNG->CR|=1<<2; //使能RNG while((RNG->SR&0X01)==0&&retry<10000) //等待随机数就绪 { retry++; delay_us(100); } if(retry>=10000)return 1;//随机数产生器工作不正常 return 0; }[/mw_shl_code]
其二,获得随机数。在随机数就绪后从随机数数据寄存器读取随机数
[mw_shl_code=c,true]//得到随机数 //返回值:获取到的随机数 u32 RNG_Get_RandomNum(void) { while((RNG->SR&0X01)==0); //等待随机数就绪 return RNG->DR; }[/mw_shl_code]
其三,得到某一范围随机数。此处有一个小算法,把随机数转换到某一限定区域中,值得品鉴。
[mw_shl_code=c,true]//得到某个范围内的随机数 //min,max,最小,最大值. //返回值:得到的随机数(rval),满足:min<=rval<=max int RNG_Get_RandomRange(int min,int max) { return RNG_Get_RandomNum()%(max-min+1)+min; }[/mw_shl_code]
以我资质之鲁钝,当尽平心静气、循序渐进、稳扎稳打之力。
回复 支持 反对

使用道具 举报

72

主题

2711

帖子

2

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
3505
金钱
3505
注册时间
2014-8-4
在线时间
696 小时
 楼主| 发表于 2015-8-8 23:23:30 | 显示全部楼层
回复【129楼】正点原子:
---------------------------------
谢老大,哈哈......
以我资质之鲁钝,当尽平心静气、循序渐进、稳扎稳打之力。
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165309
金钱
165309
注册时间
2010-12-1
在线时间
2108 小时
发表于 2015-8-9 11:39:03 | 显示全部楼层
回复【131楼】龙之谷:
---------------------------------
昨天电脑坏了。。。
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

4

主题

58

帖子

0

精华

初级会员

Rank: 2

积分
161
金钱
161
注册时间
2015-7-31
在线时间
19 小时
发表于 2015-8-9 13:36:51 | 显示全部楼层
回复【96楼】正点原子:
---------------------------------
大哥,其实我也是新手,我也是学,你发我礼物吧,
本人深山苦练20余年,一天只睡4小时,可连续编程100小时不休息,上至带项目、出方案,下至盗账号,学校不支持编程已辍学,家人不支持编程已断绝关系,老婆不支持编程已离婚,小孩不支持编程已送孤儿院,备用电源万兆光纤永不断电断网,门口已埋雷无人打扰
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165309
金钱
165309
注册时间
2010-12-1
在线时间
2108 小时
发表于 2015-8-9 14:37:42 | 显示全部楼层
回复【133楼】中二电子测控汪:
---------------------------------
可以啊,靠你的实际行动来赚取吧。

楼主要是能按时发完90天贴,我承诺送战舰F103开发板一套,此贴为证。
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

4

主题

58

帖子

0

精华

初级会员

Rank: 2

积分
161
金钱
161
注册时间
2015-7-31
在线时间
19 小时
发表于 2015-8-9 14:52:43 | 显示全部楼层
回复【134楼】正点原子:
---------------------------------
算了,我懒这么发帖麻烦,我讨厌麻烦,学到了就行了。你对开关电源有没有研究
本人深山苦练20余年,一天只睡4小时,可连续编程100小时不休息,上至带项目、出方案,下至盗账号,学校不支持编程已辍学,家人不支持编程已断绝关系,老婆不支持编程已离婚,小孩不支持编程已送孤儿院,备用电源万兆光纤永不断电断网,门口已埋雷无人打扰
回复 支持 反对

使用道具 举报

72

主题

2711

帖子

2

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
3505
金钱
3505
注册时间
2014-8-4
在线时间
696 小时
 楼主| 发表于 2015-8-9 18:31:16 | 显示全部楼层
第一九天  2015年08月09日  周日     例程:待机唤醒实验

一、基础知识

1.低功耗模式一览表



2.在这三种低功耗模式中,最低功耗的是待机模式,在此模式下,最低只要2.2uA左右电流;停机模式是次功耗的,典型电流消耗在350uA左右;最后是睡眠模式。

3.待机模式是在CM4深度睡眠模式时关闭电压调节器,整个1.2V供电区域被断电,PLL、HSI、HSE震荡器也被断电、
SRAM和寄存器内容丢失。除备份区域(RTC寄存器、RTC备份寄存器和备份SRAM)和待机电路中的寄存器外,SRAM和寄存器内容将都丢失。而从待机模式唤醒后的代码执行等同于复位后的执行(采样启动模式引脚,读取复位向量等)。电源控制/状态寄存器(PWR_CSR)将会指示内核由待机状态退出。

4.进入及退出待机模式的条件



5.进入待机模式后,除了复位引脚、RTC_AF1引脚(PC13)(如果针对入侵、时间戳、RTC闹钟输出或RTC时钟校准输出进行了配置)和WK_UP(PA0)(如果进行了配置
)等引脚外,其余所有IO引脚都将处于高阻态。

二、程序过程分析

1.主函数代码如下
[mw_shl_code=c,true]int main(void) { Stm32_Clock_Init(336,8,2,7);//设置时钟,168Mhz delay_init(168); //延时初始化 uart_init(84,115200); //初始化串口波特率为115200 LED_Init(); //初始化LED WKUP_Init(); //待机唤醒初始化 ① LCD_Init(); //初始化LCD POINT_COLOR=RED; LCD_ShowString(30,50,200,16,16,"Explorer STM32F4"); LCD_ShowString(30,70,200,16,16,"WKUP TEST"); LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTEK"); LCD_ShowString(30,110,200,16,16,"2014/5/6"); LCD_ShowString(30,130,200,16,16,"WK_UP:Stanby/WK_UP"); while(1) { LED0=!LED0; delay_ms(250); LCD_ShowNum(30, 150, test, 2, 16); } }[/mw_shl_code]
我们将WKUP_Init();函数标为①,代码开始后执行到此处,进入此函数中判断是否进入待机模式,此函数源码
[mw_shl_code=c,true]void WKUP_Init(void) { RCC->AHB1ENR|=1<<0; //使能PORTA时钟 GPIO_Set(GPIOA,PIN0,GPIO_MODE_IN,0,0,GPIO_PUPD_PD); //PA0设置 //(检查是否是正常开)机 if(Check_WKUP()==0) //② { Sys_Enter_Standby(); //不是开机,进入待机模式 } Ex_NVIC_Config(GPIO_A,0,RTIR); //PA0上升沿触发 MY_NVIC_Init(2,2,EXTI0_IRQn,2); //抢占2,子优先级2,组2 }[/mw_shl_code]
我们将Check_WKUP()函数标为②,此处是判断是否进入待机模式的判断句,如果长按3S以上PA0(WK_UP),则Check_WKUP() == 1,不会进入待机模式,接着执行其后程序,如果没有按下则直接进入待机模式。Check_WKUP()源码如下
[mw_shl_code=c,true]u8 Check_WKUP(void) { u8 t=0; u8 tx=0;//记录松开的次数 LED0=0; //亮灯DS0 while(1) { if(WKUP_KD)//已经按下了 其中 #define WKUP_KD PAin(0)//PA0 检测是否外部WK_UP按键按下 { t++; tx=0; }else { tx++; if(tx>3)//超过90ms内没有WKUP信号 { LED0=1; return 0;//错误的按键,按下次数不够 } } delay_ms(30); if(t>=100)//按下超过3秒钟 { LED0=0; //点亮DS0 return 1; //按下3s以上了 } } } [/mw_shl_code]
经过以上分析,当我们把例程下载到开发板后,我们不按下WK_UP按键,则程序直接进入待机模式,TFT屏幕是暗的,此时我们按下WK_UP按键,持续3S以上,屏幕进行显示,那么此时为什么不是PA0按键按下即退出待机模式却需要3S以上的按键按下呢?这是由于按下PA0(WK_UP)会退出待机模式,等同于复位,此时程序会重新执行,当执行到①时,又开始进行判断,如果时间短于3S则又进入了待机模式,此时屏幕还没有开始显示,整个过程从退出到再次进入我们没有观察到屏幕的显示变化,可能会以为一直处在待机模式没有触发退出。而按下PA0时间超过3S则会跳过进入待机模式这一步,执行屏幕显示。
那么,我们是否可以通过调整程序在按键按下任意长时间都能观察到退出待机模式呢?可以,将①待机模式初始化这条语句放在TFT屏幕显示之后,即while(1)前,当按下PA0低于3S我们就可以观察到屏幕闪一下,这就表明退出了待机模式。而此时长按,则不会在此进入待机模式,屏幕也会保持显示状态。
[mw_shl_code=c,true]int main(void) { Stm32_Clock_Init(336,8,2,7);//设置时钟,168Mhz delay_init(168); //延时初始化 uart_init(84,115200); //初始化串口波特率为115200 LED_Init(); //初始化LED LCD_Init(); //初始化LCD POINT_COLOR=RED; LCD_ShowString(30,50,200,16,16,"Explorer STM32F4"); LCD_ShowString(30,70,200,16,16,"WKUP TEST"); LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTEK"); LCD_ShowString(30,110,200,16,16,"2014/5/6"); LCD_ShowString(30,130,200,16,16,"WK_UP:Stanby/WK_UP");  [/mw_shl_code] [mw_shl_code=c,true] [mw_shl_code=c,true] WKUP_Init(); //待机唤醒初始化 ①[/mw_shl_code] [/mw_shl_code] [mw_shl_code=c,true] while(1) { LED0=!LED0; delay_ms(250); LCD_ShowNum(30, 150, test, 2, 16); } }[/mw_shl_code]

2.退出待机模式后再次进入待机模式

退出待机模式后,在死循环里面等待WK_UP中断的到来,在得到中断后,在中断函数里面判断WK_UP按下的时间长短,来决定是否进入待机模式,如果按下时间超过3S,则进入待机模式,否则退出中断,继续执行mian函数死循环等待。
[mw_shl_code=c,true]//中断,检测到PA0脚的一个上升沿. //中断线0线上的中断检测 void EXTI0_IRQHandler(void) { EXTI->R=1<<0; //清除LINE10上的中断标志位 if(Check_WKUP())//关机? { Sys_Enter_Standby(); } } [/mw_shl_code]

3.关于长按PA0从待机模式退出与长按PA0从中断进入待机模式的“弯弯绕”

-----(分析的不够清晰,需要的朋友从头到尾多读两遍,尽量不要在中间卡顿
有些朋友(我也在此卡住一下)可能会感到纳闷:在待机模式下长按PA0不是进入中断了吗,在中断中经过判断按下超过3S则再次进入待机模式,怎么会退出待机模式呢?注意,请看低功耗一览表,退出待机模式是通过PA0的上升沿,而非PA0上升沿中断,并且进入待机模式时已经对PA口进行了复位,没有开启上升沿中断。所以,在待机模式下,第一次按PA0是PA0的上升沿退出待机模式,而长按则是避免再次进入待机模式,此后,在运行模式下,配置PA0,再次长按PA0是通过上升沿中断判断进入了待机模式,如此往复。
可能还是有一点不太好理解,我们可以把PA0上升沿中断配置即中断函数全部去掉,换成其他按键比如KEY0/KEY1/KEY2所对应的下降沿中断来触发进入待机模式,此时,我们会发现,一上电,我们不去按任何按键,TFT没有反应,此时处在待机模式,长按PA0退出待机模式,屏幕正常显示,长按KEY0/KEY1/KEY2(根据自己配置)则再次进入待机模式。

4.待机模式下,屏幕没有显示,但是DS0仍然闪烁,只是比运行模式闪烁慢一些,这是什么原因?

请看开发指南本节最后一段话:如果你在之前开启了RTC周期性唤醒中断(比如下载了RTC实验),那么会看到DS0周期性的闪烁(周期性唤醒MCU了)。如果想去掉这种情况,请关闭RTC的周期性唤醒中断。简单办法:将CR1220电池去掉,给板子断电,等待10秒钟左右,让RTC配置全部丢失,然后装上CR1220,之后给板子上电,就不会看到DS0周期性闪烁了。【在进行实验时确实碰到此情况,还很纳闷,十分不解,直到无意中看到这句话,所以,在进行实验前,我们尽量对开发指南相关实验进行一次全局阅读,对一些注意事项进行留意,能够避免很多弯路。第一遍全局阅读尽量减少中间卡顿不仅适用于此处,很多其他地方都适用,有时候读一篇文章,在某一段有疑问,卡住了,思来想去不理解,可能在下一段就是我们需要的内容,瞬间拨开迷雾见太阳】。
以我资质之鲁钝,当尽平心静气、循序渐进、稳扎稳打之力。
回复 支持 反对

使用道具 举报

72

主题

2711

帖子

2

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
3505
金钱
3505
注册时间
2014-8-4
在线时间
696 小时
 楼主| 发表于 2015-8-9 18:39:28 | 显示全部楼层
回复【132楼】正点原子:
---------------------------------
老大,电脑坏了要记得自己修......

这战舰103开发板的礼物直接拍的我晕头转向,给力啊,动力++++++++++,压力++++++++++,希望自己能够坚持住......
以我资质之鲁钝,当尽平心静气、循序渐进、稳扎稳打之力。
回复 支持 反对

使用道具 举报

72

主题

2711

帖子

2

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
3505
金钱
3505
注册时间
2014-8-4
在线时间
696 小时
 楼主| 发表于 2015-8-9 18:43:49 | 显示全部楼层
回复【135楼】中二电子测控汪:
---------------------------------
想得到礼物,不是必须向我这么愚公移山的一步步挪,多回复帮助坛友,多发些酷贴,原子哥也会视情况给予鼓励的,在帖子中看到过原子哥送解疑老师开发板......
以我资质之鲁钝,当尽平心静气、循序渐进、稳扎稳打之力。
回复 支持 反对

使用道具 举报

72

主题

2711

帖子

2

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
3505
金钱
3505
注册时间
2014-8-4
在线时间
696 小时
 楼主| 发表于 2015-8-9 19:00:42 | 显示全部楼层
今天更新完毕,和同事一起去超市看美女去,逛完回来看极限挑战,正式进入一周的放松时段,啦啦啦
以我资质之鲁钝,当尽平心静气、循序渐进、稳扎稳打之力。
回复 支持 反对

使用道具 举报

16

主题

60

帖子

0

精华

初级会员

Rank: 2

积分
197
金钱
197
注册时间
2015-8-9
在线时间
19 小时
发表于 2015-8-9 19:04:24 | 显示全部楼层
楼主向你学习
犯错不可怕,可怕的是不敢面对它
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165309
金钱
165309
注册时间
2010-12-1
在线时间
2108 小时
发表于 2015-8-9 21:20:36 | 显示全部楼层
回复【135楼】中二电子测控汪:
---------------------------------
没有研究哦
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165309
金钱
165309
注册时间
2010-12-1
在线时间
2108 小时
发表于 2015-8-9 21:21:02 | 显示全部楼层
回复【137楼】龙之谷:
---------------------------------
电源坏了,等待新电源中....
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165309
金钱
165309
注册时间
2010-12-1
在线时间
2108 小时
发表于 2015-8-10 22:54:09 | 显示全部楼层
今天啥时候更新?
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

72

主题

2711

帖子

2

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
3505
金钱
3505
注册时间
2014-8-4
在线时间
696 小时
 楼主| 发表于 2015-8-10 23:43:48 | 显示全部楼层
第二十天  2015年08月10日  周一     例程:ADC实验 



1.STM32F4的ADC是12位逐次逼近型的模拟数字转换器。它有19个通道,可测量16个外部源、2个内部源和Vbat通道的信号。
2.STM32F407ZGT6包含3个ADC,最大转换速率为2.4Mhz,转换时间为0.41us(当ADCCLK=36Mhz,采样周期为3个ADC时钟),不要让ADC时钟超过36Mhz,否则将导致结果准确度下降。
3.STM32F4的ADC转换分为2个通道组:规则通道和注入通道。规则通道相当于正常运行的程序,注入通道相当于中断,注入通道可以打断规则通道的转换,在注入通道完成转换后,规则通道才能进行转换。规则通道组最多包含16个转换,而注入通道组最多包含4个通道。
4.STM32F407ZGT6只有Vref+参考电压引脚,输入范围为1.8~VDDA。探索者开发板通过P7端口将Vref+接到VDDA,也就是参考电压是3.3V。对于还有Vref-引脚的STM32F4芯片,直接就进将Vref-接VSSA即可。
5.探索者默认情况是通过P12将ADC引脚和TPAD进行了短接,所以上电后显示电压在3.1V左右,此时可摘掉短路帽,通过杜邦线连接电压值低于参考点电压进行测量。当接地时有十毫伏左右电压,接3.3V输出时有不到3.3V电压。
6.在主函数中电压值temp = (float)adcx*(3.3/4096);而adcx则是通过return ADC1->DR;这个寄存器的低12位而来,所以adcx最大值为4095,也就是即使理论上,所测量电压值也不会达到3.3V,最多是4095*(3.3 /4096),这是与我们预期相矛盾的一个小点。因而,电压值计算公式应为 temp = (float)adcx*(3.3/4095)。
7.获取多次测量平均值函数
[mw_shl_code=c,true]/********************************************************* 功能 :获取times次通道ch转换值,返回平均数 *********************************************************/ u16 Get_Adc_Average(u8 ch, u8 times) { u8 t; u32 temp_val = 0; for(t=0; t<times; t++) { temp_val += Get_Adc(ch); delay_ms(5); } return temp_val / times; }[/mw_shl_code]
此函数,虽无多大难度,但整个实现过程简单明了,无半点拖泥带水,值得我们在对程序编写的时候进行借鉴与模仿。




TFTLCD显示实验【一】-----字符显示函数汇总
uint LCD_Pow(uchar m, uchar n);
函数作用:m的n次方。     这是分析显示函数,顺带着此函数,抱着③的大腿来的。

void LCD_ShowChar(uint x, uint y, uchar num, uchar size, uchar mode);
函数作用:在指定位置显示一个字符。    
参数含义:x,y:起始坐标;  num:要显示的字符:" "--->"~";  size:字体大小 12/16/24;  mode:叠加方式(1)还是非叠加方式(0)

void LCD_ShowNum(uint x, uint y, uint num, uchar len, uchar size);
函数作用:显示数字,高位为0,则不显示
参数含义:x,y :起点坐标;  len :数字的位数;  size:字体大小;  color:颜色;  num:数值(0~4294967295);

void LCD_ShowxNum(uint x, uint y, uint num, uchar len, uchar size, uchar mode);
函数作用:显示数字,高位为0,据需显示
参数含义:x,y:起点坐标;  num:数值(0~999999999);  len:长度(即要显示的位数);  size:字体大小;
                mode--[7]:0,不填充;1,填充0.  [6:1]:保留  [0]:0,非叠加显示;1,叠加显示.

void LCD_ShowString(uint x, uint y, uint width, uint height, uchar size, uchar *p);
函数作用:显示字符串
参数含义:x,y:起点坐标;  width,height:区域大小;  size:字体大小;  p:字符串起始地址;
-----------------------------------------------------------------------------------------------------------------------------------------------
[mw_shl_code=c,true]/********************************************************************* 功能 :m^n函数 ********************************************************************************************/ uint LCD_Pow(uchar m, uchar n) { uint result = 1; while(n--) { result *= m; } return result; }[/mw_shl_code]

[mw_shl_code=c,true]void LCD_ShowChar(uint x, uint y, uchar num, uchar size, uchar mode) { uchar temp, t1, t; uint y0 = y; uchar csize = (size/8+((size%8)?1:0))*(size/2); //注1 num = num - ' '; //注2 for(t=0; t<csize; t++) //注3 { if(size == 12) { temp = asc2_1206[num][t]; } else if(size == 16) { temp = asc2_1608[num][t]; } else if(size == 24) { temp = asc2_2412[num][t]; } else { return; } for(t1=0; t1<8; t1++) { if(temp & 0x80) { LCD_Fast_DrawPoint(x, y, POINT_COLOR); } else if(mode == 0) { LCD_Fast_DrawPoint(x, y, BACK_COLOR); } temp <<= 1; y++; if(y >= lcddev.height) { return; } if(y - y0 == size) { y = y0; x++; if(x >= lcddev.width) { return; } break; } } } }[/mw_shl_code]
[mw_shl_code=c,true][/mw_shl_code]
注1:csize = (size/8+((size%8)?1:0))*(size/2);通过字体大小确定确定点阵字节数。个人认为(还需进一步确认),屏幕是逐列进行扫描,由于字符宽度一般为高度一半,故共size/2列;而横向则是每八行即一个字节进行送数,如果行数是8的整倍数,则横向扫描一次送size/8字节数据,但是如果行数不是8的倍数,因为每次必然传送一个字节进行扫描,不可能拆开,而每个字节控制8行,所以不足8行也会按照一个字节进行处理,因而当有不足八行出现时((size%8)?1:0),也就是不足一个字节按照一个字节来处理。
注2:num = num - ' ';通过所给num判断其所在数组位置。减号后边的‘ ’是第0个字符,空字符,也即0x20。通过当前需显示字符减去第0个字符,偏移量即是num数组起始地址,也就是二维数组第一个下角标的数值。再加上size确定了是字符集点阵(二维数组),两个变量配合将num字符点阵数据进行了锁定。
注3:for(t=0; t<csize; t++)循环中将锁定的点阵数据逐个进行传送,没传送一个字节,则对某一列的连续8个点阵进行判断,如果为1,则打点显示,直到行数扫描完成,列数右移一个点阵,依次循环。

[mw_shl_code=c,true]void LCD_ShowNum(uint x, uint y, uint num, uchar len, uchar size) { uchar t, temp, enshow = 0; for(t=0; t<len; t++) { temp = (num / LCD_Pow(10, len - t - 1)) % 10; //将多位数依次拆为0~9的个位数进行逐个处理 if(enshow==0 && t < len - 1) //注4 { if(temp==0) { LCD_ShowChar(x+(size/2)*t, y, ' ', size, 0); continue; } else { enshow = 1; } } LCD_ShowChar(x + (size / 2) * t, y, temp + '0', size, 0); //注5 } }[/mw_shl_code]
注4:enshow,控制高位为零时显示空(即不显示),而一旦出现有效字符则置位跳过检测,其后字符按序显示。
注5:显示对应数字,temp+‘0’即(temp-0)+‘0’,就是数字在0的偏移量对应到数字在字符‘0’的偏移量,从而得到显示字符数据。

[mw_shl_code=c,true]void LCD_ShowxNum(uint x, uint y, uint num, uchar len, uchar size, uchar mode) { uchar t, temp, enshow = 0; for(t=0; t<len; t++) { temp = (num / LCD_Pow(10, len - t - 1)) % 10; if(enshow==0 && t < len - 1) { if(temp==0) { if(mode&0x80) //注6 { LCD_ShowChar(x+(size/2)*t, y, '0', size, mode&0x01); } else { LCD_ShowChar(x+(size/2)*t, y, ' ', size, mode&0x01); } continue; //注7 } else { enshow = 1; } } LCD_ShowChar(x + (size / 2) * t, y, temp + '0', size, mode&0x01); } }[/mw_shl_code]
注6:通过mode的最高位判断最高位是0时是否显示,是在函数③的基础上进行了一下扩展,从而满足更宽范围的显示需要。
注7:continue,跳过循环中其后语句,继续下一次循环,在此处完成特殊显示(高位0的处理)与一般显示(有效数字)的切割,使其互相独立,共同构成一个整体。

[mw_shl_code=c,true]void LCD_ShowString(uint x, uint y, uint width, uint height, uchar size, uchar *p) { uchar x0 = x; width += x; height += y; while((*p<='~')&&(*p>=' ')) //注8 { if(x>=width) { x = x0; y += size; } if(y > height) { break; } LCD_ShowChar(x, y, *p, size, 0); //注9 x += size / 2; p++; } } [/mw_shl_code]
注8:空字符‘ ’是起始有效显示字符,而‘~’则是结尾有效显示字符,通过此处进行判断字符是否合法。
注9:当字符有效时,通过对字符显示位置的处理,调用字符显示函数将字符串中的字符逐个进行显示。

以我资质之鲁钝,当尽平心静气、循序渐进、稳扎稳打之力。
回复 支持 反对

使用道具 举报

72

主题

2711

帖子

2

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
3505
金钱
3505
注册时间
2014-8-4
在线时间
696 小时
 楼主| 发表于 2015-8-11 01:46:32 | 显示全部楼层
回复【143楼】正点原子:
---------------------------------
本以为今天更新的内容不多,没怎么抓紧时间,结果......

老大,发表十几天以后就不能再编辑了呀,本来打算在楼主位加个目录来着,发现不让编辑了
以我资质之鲁钝,当尽平心静气、循序渐进、稳扎稳打之力。
回复 支持 反对

使用道具 举报

18

主题

105

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
377
金钱
377
注册时间
2013-3-1
在线时间
50 小时
发表于 2015-8-11 10:22:42 | 显示全部楼层
支持下楼主

有问题共同探讨。
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165309
金钱
165309
注册时间
2010-12-1
在线时间
2108 小时
发表于 2015-8-11 10:44:22 | 显示全部楼层
回复【145楼】龙之谷:
---------------------------------
我可以编辑
到时候你整理好了,我帮你做目录。
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

72

主题

2711

帖子

2

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
3505
金钱
3505
注册时间
2014-8-4
在线时间
696 小时
 楼主| 发表于 2015-8-11 23:47:33 | 显示全部楼层
第二一天  2015年08月11日  周二     例程:内部温度传感器实验



1.STM32F4有一个内部温度传感器,可以用来测量CPU及周围的温度。此温度传感器在内部和ADC1_IN16(STM32F40xx系列)或ADC1_IN18(STM32F42cxx/STM32F43xx系列)输入通道相连接,可以把传感器输出的电压转换为数字值。
2.支持温度范围:-40~125℃,精度±1.5。
3.温度计算公式:T(℃) = ((Vsense - V25) / Avg_Slope) + 25;
其中,V25 = Vsense在25℃时的数值(典型值0.76)
Avg_Slope = 温度与Vsense曲线的平均斜率(mv/℃或uv/℃)(典型值2.5mv/℃
Vsense为内部传感器输出电压转换后的数字值



TFTLCD显示实验【二】-----图形绘制函数汇总(开发指南的搬运工)
①void LCD_SetCursor(u16 Xpos, u16 Ypos);
函数作用:设置光标位置
参数含义:Xpos:横坐标;  Ypos:纵坐标

②void LCD_DrawPoint(u16 x,u16 y);
函数作用:画点
参数含义:x,y:坐标;  OINT_COLOR:此点的颜色

void LCD_Fast_DrawPoint(u16 x,u16 y,u16 color);
函数作用:快速画点
参数含义:x,y:坐标;  color:颜色

③u16 LCD_ReadPoint(u16 x,u16 y);
函数作用:读取个某点的颜色值
参数含义:x,y:坐标;  返回值:此点的颜色

④void LCD_Display_Dir(u8 dir);
函数作用:设置LCD显示方向
参数含义:dir:0,竖屏;1,横屏

⑤void LCD_Set_Window(u16 sx,u16 sy,u16 width,u16 height);
函数作用:设置窗口,并自动设置画点坐标到窗口左上角(sx,sy).
参数含义:sx,sy:窗口起始坐标(左上角);  width,height:窗口宽度和高度,必须大于0!!  窗体大小:width*height.
                //68042,横屏时不支持窗口设置!! 

⑥void LCD_Clear(u16 color);
函数作用:清屏函数
参数含义:color:要清屏的填充色

⑦void LCD_Fill(u16 sx,u16 sy,u16 ex,u16 ey,u16 color);
函数作用:在指定区域内填充单个颜色
参数含义:(sx,sy),(ex,ey):填充矩形对角坐标,区域大小为ex-sx+1)*(ey-sy+1)     color:要填充的颜色

⑧void LCD_Color_Fill(u16 sx,u16 sy,u16 ex,u16 ey,u16 *color);
函数作用:在指定区域内填充指定颜色块
参数含义:(sx,sy),(ex,ey):填充矩形对角坐标,区域大小为ex-sx+1)*(ey-sy+1)     color:要填充的颜色

⑨void LCD_DrawLine(u16 x1, u16 y1, u16 x2, u16 y2);
函数作用:画线
参数含义:x1,y1:起点坐标;  x2,y2:终点坐标 

⑩void LCD_DrawRectangle(u16 x1, u16 y1, u16 x2, u16 y2);
函数作用:画矩形
参数含义:(x1,y1),(x2,y2):矩形的对角坐标

void LCD_Draw_Circle(u16 x0,u16 y0,u8 r);
函数作用:在指定位置画一个指定大小的圆
参数含义:(x,y):中心点;  r   :半径

--------------------------------------------------------------------------------------------------------------------------------------------

[mw_shl_code=c,true]//设置光标位置 //Xpos:横坐标 //Ypos:纵坐标 void LCD_SetCursor(u16 Xpos, u16 Ypos) { if(lcddev.id==0X9341||lcddev.id==0X5310) { LCD_WR_REG(lcddev.setxcmd); LCD_WR_DATA(Xpos>>8); LCD_WR_DATA(Xpos&0XFF); LCD_WR_REG(lcddev.setycmd); LCD_WR_DATA(Ypos>>8); LCD_WR_DATA(Ypos&0XFF); }else if(lcddev.id==0X6804) { if(lcddev.dir==1)Xpos=lcddev.width-1-Xpos;//横屏时处理 LCD_WR_REG(lcddev.setxcmd); LCD_WR_DATA(Xpos>>8); LCD_WR_DATA(Xpos&0XFF); LCD_WR_REG(lcddev.setycmd); LCD_WR_DATA(Ypos>>8); LCD_WR_DATA(Ypos&0XFF); }else if(lcddev.id==0X5510) { LCD_WR_REG(lcddev.setxcmd); LCD_WR_DATA(Xpos>>8); LCD_WR_REG(lcddev.setxcmd+1); LCD_WR_DATA(Xpos&0XFF); LCD_WR_REG(lcddev.setycmd); LCD_WR_DATA(Ypos>>8); LCD_WR_REG(lcddev.setycmd+1); LCD_WR_DATA(Ypos&0XFF); }else { if(lcddev.dir==1)Xpos=lcddev.width-1-Xpos;//横屏其实就是调转x,y坐标 LCD_WriteReg(lcddev.setxcmd, Xpos); LCD_WriteReg(lcddev.setycmd, Ypos); } } [/mw_shl_code]

[mw_shl_code=c,true]//画点 //x,y:坐标 //POINT_COLOR:此点的颜色 void LCD_DrawPoint(u16 x,u16 y) { LCD_SetCursor(x,y); //设置光标位置 LCD_WriteRAM_Prepare(); //开始写入GRAM LCD->LCD_RAM=POINT_COLOR; } //快速画点 //x,y:坐标 //color:颜色 void LCD_Fast_DrawPoint(u16 x,u16 y,u16 color) { if(lcddev.id==0X9341||lcddev.id==0X5310) { LCD_WR_REG(lcddev.setxcmd); LCD_WR_DATA(x>>8); LCD_WR_DATA(x&0XFF); LCD_WR_REG(lcddev.setycmd); LCD_WR_DATA(y>>8); LCD_WR_DATA(y&0XFF); }else if(lcddev.id==0X5510) { LCD_WR_REG(lcddev.setxcmd);LCD_WR_DATA(x>>8); LCD_WR_REG(lcddev.setxcmd+1);LCD_WR_DATA(x&0XFF); LCD_WR_REG(lcddev.setycmd);LCD_WR_DATA(y>>8); LCD_WR_REG(lcddev.setycmd+1);LCD_WR_DATA(y&0XFF); }else if(lcddev.id==0X6804) { if(lcddev.dir==1)x=lcddev.width-1-x;//横屏时处理 LCD_WR_REG(lcddev.setxcmd); LCD_WR_DATA(x>>8); LCD_WR_DATA(x&0XFF); LCD_WR_REG(lcddev.setycmd); LCD_WR_DATA(y>>8); LCD_WR_DATA(y&0XFF); }else { if(lcddev.dir==1)x=lcddev.width-1-x;//横屏其实就是调转x,y坐标 LCD_WriteReg(lcddev.setxcmd,x); LCD_WriteReg(lcddev.setycmd,y); } LCD->LCD_REG=lcddev.wramcmd; LCD->LCD_RAM=color; } [/mw_shl_code]

[mw_shl_code=c,true]//读取个某点的颜色值 //x,y:坐标 //返回值:此点的颜色 u16 LCD_ReadPoint(u16 x,u16 y) { vu16 r=0,g=0,b=0; if(x>=lcddev.width||y>=lcddev.height)return 0; //超过了范围,直接返回 LCD_SetCursor(x,y); if(lcddev.id==0X9341||lcddev.id==0X6804||lcddev.id==0X5310)LCD_WR_REG(0X2E);//9341/6804/3510 发送读GRAM指令 else if(lcddev.id==0X5510)LCD_WR_REG(0X2E00); //5510 发送读GRAM指令 else LCD_WR_REG(R34); //其他IC发送读GRAM指令 if(lcddev.id==0X9320)opt_delay(2); //FOR 9320,延时2us LCD_RD_DATA(); //dummy Read opt_delay(2); r=LCD_RD_DATA(); //实际坐标颜色 if(lcddev.id==0X9341||lcddev.id==0X5310||lcddev.id==0X5510) //9341/NT35310/NT35510要分2次读出 { opt_delay(2); b=LCD_RD_DATA(); g=r&0XFF; //对于9341/5310/5510,第一次读取的是RG的值,R在前,G在后,各占8位 g<<=8; } if(lcddev.id==0X9325||lcddev.id==0X4535||lcddev.id==0X4531||lcddev.id==0XB505||lcddev.id==0XC505)return r; //这几种IC直接返回颜色值 else if(lcddev.id==0X9341||lcddev.id==0X5310||lcddev.id==0X5510)return (((r>>11)<<11)|((g>>10)<<5)|(b>>11));//ILI9341/NT35310/NT35510需要公式转换一下 else return LCD_BGR2RGB(r); //其他IC }[/mw_shl_code]

[mw_shl_code=c,true]//设置LCD显示方向 //dir:0,竖屏;1,横屏 void LCD_Display_Dir(u8 dir) { if(dir==0) //竖屏 { lcddev.dir=0; //竖屏 lcddev.width=240; lcddev.height=320; if(lcddev.id==0X9341||lcddev.id==0X6804||lcddev.id==0X5310) { lcddev.wramcmd=0X2C; lcddev.setxcmd=0X2A; lcddev.setycmd=0X2B; if(lcddev.id==0X6804||lcddev.id==0X5310) { lcddev.width=320; lcddev.height=480; } }else if(lcddev.id==0x5510) { lcddev.wramcmd=0X2C00; lcddev.setxcmd=0X2A00; lcddev.setycmd=0X2B00; lcddev.width=480; lcddev.height=800; }else { lcddev.wramcmd=R34; lcddev.setxcmd=R32; lcddev.setycmd=R33; } }else //横屏 { lcddev.dir=1; //横屏 lcddev.width=320; lcddev.height=240; if(lcddev.id==0X9341||lcddev.id==0X5310) { lcddev.wramcmd=0X2C; lcddev.setxcmd=0X2A; lcddev.setycmd=0X2B; }else if(lcddev.id==0X6804) { lcddev.wramcmd=0X2C; lcddev.setxcmd=0X2B; lcddev.setycmd=0X2A; }else if(lcddev.id==0x5510) { lcddev.wramcmd=0X2C00; lcddev.setxcmd=0X2A00; lcddev.setycmd=0X2B00; lcddev.width=800; lcddev.height=480; }else { lcddev.wramcmd=R34; lcddev.setxcmd=R33; lcddev.setycmd=R32; } if(lcddev.id==0X6804||lcddev.id==0X5310) { lcddev.width=480; lcddev.height=320; } } LCD_Scan_Dir(DFT_SCAN_DIR); //默认扫描方向 } [/mw_shl_code]

[mw_shl_code=c,true]//设置窗口,并自动设置画点坐标到窗口左上角(sx,sy). //sx,sy:窗口起始坐标(左上角) //width,height:窗口宽度和高度,必须大于0!! //窗体大小:width*height. //68042,横屏时不支持窗口设置!! void LCD_Set_Window(u16 sx,u16 sy,u16 width,u16 height) { u8 hsareg,heareg,vsareg,veareg; u16 hsaval,heaval,vsaval,veaval; width=sx+width-1; height=sy+height-1; if(lcddev.id==0X9341||lcddev.id==0X5310||lcddev.id==0X6804)//6804横屏不支持 { LCD_WR_REG(lcddev.setxcmd); LCD_WR_DATA(sx>>8); LCD_WR_DATA(sx&0XFF); LCD_WR_DATA(width>>8); LCD_WR_DATA(width&0XFF); LCD_WR_REG(lcddev.setycmd); LCD_WR_DATA(sy>>8); LCD_WR_DATA(sy&0XFF); LCD_WR_DATA(height>>8); LCD_WR_DATA(height&0XFF); }else if(lcddev.id==0X5510) { LCD_WR_REG(lcddev.setxcmd);LCD_WR_DATA(sx>>8); LCD_WR_REG(lcddev.setxcmd+1);LCD_WR_DATA(sx&0XFF); LCD_WR_REG(lcddev.setxcmd+2);LCD_WR_DATA(width>>8); LCD_WR_REG(lcddev.setxcmd+3);LCD_WR_DATA(width&0XFF); LCD_WR_REG(lcddev.setycmd);LCD_WR_DATA(sy>>8); LCD_WR_REG(lcddev.setycmd+1);LCD_WR_DATA(sy&0XFF); LCD_WR_REG(lcddev.setycmd+2);LCD_WR_DATA(height>>8); LCD_WR_REG(lcddev.setycmd+3);LCD_WR_DATA(height&0XFF); }else //其他驱动IC { if(lcddev.dir==1)//横屏 { //窗口值 hsaval=sy; heaval=height; vsaval=lcddev.width-width-1; veaval=lcddev.width-sx-1; }else { hsaval=sx; heaval=width; vsaval=sy; veaval=height; } hsareg=0X50;heareg=0X51;//水平方向窗口寄存器 vsareg=0X52;veareg=0X53;//垂直方向窗口寄存器 //设置寄存器值 LCD_WriteReg(hsareg,hsaval); LCD_WriteReg(heareg,heaval); LCD_WriteReg(vsareg,vsaval); LCD_WriteReg(veareg,veaval); LCD_SetCursor(sx,sy); //设置光标位置 } } [/mw_shl_code]

[mw_shl_code=c,true]//清屏函数 //color:要清屏的填充色 void LCD_Clear(u16 color) { u32 index=0; u32 totalpoint=lcddev.width; totalpoint*=lcddev.height; //得到总点数 if((lcddev.id==0X6804)&&(lcddev.dir==1))//6804横屏的时候特殊处理 { lcddev.dir=0; lcddev.setxcmd=0X2A; lcddev.setycmd=0X2B; LCD_SetCursor(0x00,0x0000); //设置光标位置 lcddev.dir=1; lcddev.setxcmd=0X2B; lcddev.setycmd=0X2A; }else LCD_SetCursor(0x00,0x0000); //设置光标位置 LCD_WriteRAM_Prepare(); //开始写入GRAM for(index=0;index<totalpoint;index++) { LCD->LCD_RAM=color; } } [/mw_shl_code]

[mw_shl_code=c,true]//在指定区域内填充单个颜色 //(sx,sy),(ex,ey):填充矩形对角坐标,区域大小为ex-sx+1)*(ey-sy+1) //color:要填充的颜色 void LCD_Fill(u16 sx,u16 sy,u16 ex,u16 ey,u16 color) { u16 i,j; u16 xlen=0; u16 temp; if((lcddev.id==0X6804)&&(lcddev.dir==1)) //6804横屏的时候特殊处理 { temp=sx; sx=sy; sy=lcddev.width-ex-1; ex=ey; ey=lcddev.width-temp-1; lcddev.dir=0; lcddev.setxcmd=0X2A; lcddev.setycmd=0X2B; LCD_Fill(sx,sy,ex,ey,color); lcddev.dir=1; lcddev.setxcmd=0X2B; lcddev.setycmd=0X2A; }else { xlen=ex-sx+1; for(i=sy;i<=ey;i++) { LCD_SetCursor(sx,i); //设置光标位置 LCD_WriteRAM_Prepare(); //开始写入GRAM for(j=0;j<xlen;j++)LCD->LCD_RAM=color; //显示颜色 } } } [/mw_shl_code]

[mw_shl_code=c,true]//在指定区域内填充指定颜色块 //(sx,sy),(ex,ey):填充矩形对角坐标,区域大小为ex-sx+1)*(ey-sy+1) //color:要填充的颜色 void LCD_Color_Fill(u16 sx,u16 sy,u16 ex,u16 ey,u16 *color) { u16 height,width; u16 i,j; width=ex-sx+1; //得到填充的宽度 height=ey-sy+1; //高度 for(i=0;i<height;i++) { LCD_SetCursor(sx,sy+i); //设置光标位置 LCD_WriteRAM_Prepare(); //开始写入GRAM for(j=0;j<width;j++)LCD->LCD_RAM=color[i*width+j];//写入数据 } } [/mw_shl_code]

[mw_shl_code=c,true]//画线 //x1,y1:起点坐标 //x2,y2:终点坐标 void LCD_DrawLine(u16 x1, u16 y1, u16 x2, u16 y2) { u16 t; int xerr=0,yerr=0,delta_x,delta_y,distance; int incx,incy,uRow,uCol; delta_x=x2-x1; //计算坐标增量 delta_y=y2-y1; uRow=x1; uCol=y1; if(delta_x>0)incx=1; //设置单步方向 else if(delta_x==0)incx=0;//垂直线 else {incx=-1;delta_x=-delta_x;} if(delta_y>0)incy=1; else if(delta_y==0)incy=0;//水平线 else{incy=-1;delta_y=-delta_y;} if( delta_x>delta_y)distance=delta_x; //选取基本增量坐标轴 else distance=delta_y; for(t=0;t<=distance+1;t++ )//画线输出 { LCD_DrawPoint(uRow,uCol);//画点 xerr+=delta_x ; yerr+=delta_y ; if(xerr>distance) { xerr-=distance; uRow+=incx; } if(yerr>distance) { yerr-=distance; uCol+=incy; } } } [/mw_shl_code]

[mw_shl_code=c,true]//画矩形 //(x1,y1),(x2,y2):矩形的对角坐标 void LCD_DrawRectangle(u16 x1, u16 y1, u16 x2, u16 y2) { LCD_DrawLine(x1,y1,x2,y1); LCD_DrawLine(x1,y1,x1,y2); LCD_DrawLine(x1,y2,x2,y2); LCD_DrawLine(x2,y1,x2,y2); }[/mw_shl_code]

[mw_shl_code=c,true]//在指定位置画一个指定大小的圆 //(x,y):中心点 //r :半径 void LCD_Draw_Circle(u16 x0,u16 y0,u8 r) { int a,b; int di; a=0;b=r; di=3-(r<<1); //判断下个点位置的标志 while(a<=b) { LCD_DrawPoint(x0+a,y0-b); //5 LCD_DrawPoint(x0+b,y0-a); //0 LCD_DrawPoint(x0+b,y0+a); //4 LCD_DrawPoint(x0+a,y0+b); //6 LCD_DrawPoint(x0-a,y0+b); //1 LCD_DrawPoint(x0-b,y0+a); LCD_DrawPoint(x0-a,y0-b); //2 LCD_DrawPoint(x0-b,y0-a); //7 a++; //使用Bresenham算法画圆 if(di<0)di +=4*a+6; else { di+=10+4*(a-b); b--; } } } [/mw_shl_code]

总结:通过对以上程序进行汇总,可以发现,初看程序量较大,对每个函数稍微进行分析即可看出,除画圆等需要一定算法(无需过多涉猎)外,其他函数都是在进行了少量转化后进行屏幕寄存器的基础操作,也就是对常用寄存器的熟悉程度是处理好此类函数的关键。
以我资质之鲁钝,当尽平心静气、循序渐进、稳扎稳打之力。
回复 支持 反对

使用道具 举报

72

主题

2711

帖子

2

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
3505
金钱
3505
注册时间
2014-8-4
在线时间
696 小时
 楼主| 发表于 2015-8-12 00:01:03 | 显示全部楼层
回复【146楼】huarana:
---------------------------------
欢迎欢迎,热烈欢迎、、、
以我资质之鲁钝,当尽平心静气、循序渐进、稳扎稳打之力。
回复 支持 反对

使用道具 举报

72

主题

2711

帖子

2

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
3505
金钱
3505
注册时间
2014-8-4
在线时间
696 小时
 楼主| 发表于 2015-8-12 00:05:45 | 显示全部楼层
回复【147楼】正点原子:
---------------------------------
好嘞,等更新差不多了我整理整理
以我资质之鲁钝,当尽平心静气、循序渐进、稳扎稳打之力。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-11-22 11:27

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表