F429免费提供接口的网站的接口有哪些

网站已改版,请使用新地址访问:
OV2640 秉火 200W摄像头模块 可直接插到 F429 中使用,有专用的接口 SCM 单片机开发 252万源代码下载- www.pudn.com
&文件名称: OV2640& & [
& & & & &&]
&&所属分类:
&&开发工具: C-C++
&&文件大小: 2058 KB
&&上传时间:
&&下载次数: 0
&&提 供 者:
&详细说明:秉火 OVW摄像头模块 可直接插到 秉火 F429 中使用,有专用的接口-Bing fire OVW camera module can be directly inserted into the use of fire Bing F429, a special interface
文件列表(点击判断是否您需要的文件,如果是垃圾请在下面评价投诉):
&&摄像头―OV2640&&..............\1-原理图&&..............\........\ov2640―彩色原理图.pdf&&..............\........\ov2640―黑白原理图(可A4纸打印).pdf&&..............\2-程序&&..............\......\DCMI―OV2640摄像头.zip&&..............\3-数据手册&&..............\..........\ov2640datasheet.pdf&&..............\4-封装库&&..............\........\AD封装库&&..............\........\........\OV2640.PcbLib&&..............\........\........\OV2640.SCHLIB&&..............\........\........\OV2640_外形结构图.pcb&&..............\........\PADS封装库&&..............\........\..........\OV2640_SCH.p&&..............\........\..........\OV2640_外形结构图.pcb&&..............\........\..........\OV2640外形尺寸图.jpg&&..............\OV2640与F429接线方式.jpg&&..............\OV2640与F429接线方式.xls&&..............\【必看】OV2640使用方法.txt
&输入关键字,在本站252万海量源码库中尽情搜索:(window.slotbydup=window.slotbydup || []).push({
id: '2014386',
container: s,
size: '234,60',
display: 'inlay-fix'
&&|&&0次下载&&|&&总314页&&|
您的计算机尚未安装Flash,点击安装&
阅读已结束,如需下载到电脑,请使用积分()
下载:100积分
0人评价3页
0人评价3页
0人评价2页
0人评价4页
0人评价1页
0人评价3页
所需积分:(友情提示:大部分文档均可免费预览!下载之前请务必先预览阅读,以免误下载造成积分浪费!)
(多个标签用逗号分隔)
文不对题,内容与标题介绍不符
广告内容或内容过于简单
文档乱码或无法正常显示
文档内容侵权
已存在相同文档
不属于经济管理类文档
源文档损坏或加密
若此文档涉嫌侵害了您的权利,请参照说明。
我要评价:
价格:100积分VIP价:80积分21ic官方微信-->
用什么对接方式能把12个网口方便的对接?
高级技术员, 积分 662, 距离下一级还需 338 积分
高级技术员, 积分 662, 距离下一级还需 338 积分
高级技术员, 积分 662, 距离下一级还需 338 积分
高级技术员, 积分 662, 距离下一级还需 338 积分
大家好,我公司产线需要改造,如图,本来是为电脑做老化测试用,一共有9个网口,现在希望老化车可以移动,希望用一个接头对插方式省下人工插网线,用什么接头或方式比较好(要耐用)?谢谢。
本帖子中包含更多资源
才可以下载或查看,没有帐号?
花点银子,改成无线的,哈哈,小心老板打pp
助理工程师, 积分 1700, 距离下一级还需 300 积分
助理工程师, 积分 1700, 距离下一级还需 300 积分
助理工程师, 积分 1700, 距离下一级还需 300 积分
助理工程师, 积分 1700, 距离下一级还需 300 积分
放个16口//交//换机到架子上即可,只要插拔1根网线
高级技术员, 积分 662, 距离下一级还需 338 积分
高级技术员, 积分 662, 距离下一级还需 338 积分
高级技术员, 积分 662, 距离下一级还需 338 积分
高级技术员, 积分 662, 距离下一级还需 338 积分
放个16口//交//换机到架子上即可,只要插拔1根网线
1條網線最高的速度是1GB(理想),如果這樣一分下來9個網口速度也只有100M(理想)。速度達不到公司要求,公司要求每個口要達到500MB以上
技术总监, 积分 31190, 距离下一级还需 18810 积分
技术总监, 积分 31190, 距离下一级还需 18810 积分
技术总监, 积分 31190, 距离下一级还需 18810 积分
技术总监, 积分 31190, 距离下一级还需 18810 积分
用板对板连接器,如“96pin欧式插座”
高级工程师, 积分 5410, 距离下一级还需 2590 积分
高级工程师, 积分 5410, 距离下一级还需 2590 积分
高级工程师, 积分 5410, 距离下一级还需 2590 积分
高级工程师, 积分 5410, 距离下一级还需 2590 积分
9个口都要500M以上,那我想问它们接到什么机子上。难道那边不是交换机?
提示: 作者被禁止或删除 内容自动屏蔽
高速多数据线插口,估计数显卡插槽吧。
中级技术员, 积分 228, 距离下一级还需 72 积分
中级技术员, 积分 228, 距离下一级还需 72 积分
中级技术员, 积分 228, 距离下一级还需 72 积分
中级技术员, 积分 228, 距离下一级还需 72 积分
5M以内可以用SFP+铜缆,不知插拔寿命如何,速度10Gbps。
提示: 作者被禁止或删除 内容自动屏蔽
中级技术员, 积分 228, 距离下一级还需 72 积分
中级技术员, 积分 228, 距离下一级还需 72 积分
中级技术员, 积分 228, 距离下一级还需 72 积分
中级技术员, 积分 228, 距离下一级还需 72 积分
这类高速铜缆都是PCB卡,用量远不及PCIe槽,因此座和头都死贵。
我们用SFF-8644,单口座价格36元,寿命5 ...
想了想寿命确实不行,这种高速线本来就不是想让用户频繁插拔的。价格倒是其次,定制产品贵点也就算了。
不过PCIE槽的寿命感觉也让人担忧,还有牢固程度也是问题,如果加其他固定方式,感觉还不如插那几根网线。
提示: 作者被禁止或删除 内容自动屏蔽
高级工程师, 积分 5410, 距离下一级还需 2590 积分
高级工程师, 积分 5410, 距离下一级还需 2590 积分
高级工程师, 积分 5410, 距离下一级还需 2590 积分
高级工程师, 积分 5410, 距离下一级还需 2590 积分
刚刚从代工厂回家,工厂测PCIe卡,是在主板上先插一个转接板,然后PCIe卡再插到转接板上,平均一周换一块转 ...
这样的作用其实是降低主板上的插槽磨损速度.把高磨损转移到便宜的转接板上.毕竟主板换插槽成本不低(其实是人工成本高),也不能换几次,换多了主板会挂.
车间里面看环境
如果是低尘少污染车间,可以用笔记本内存的那种安装方式,这种卡式结构要比台式机的插式磨损量小得多.
其实问题还在于,你这样做一个连接器的成本有没有比你9根网线低.
提示: 作者被禁止或删除 内容自动屏蔽
高级工程师, 积分 5410, 距离下一级还需 2590 积分
高级工程师, 积分 5410, 距离下一级还需 2590 积分
高级工程师, 积分 5410, 距离下一级还需 2590 积分
高级工程师, 积分 5410, 距离下一级还需 2590 积分
楼主要解决的问题,是方便一次就插上这些网线,而不是一个个地把这些网线插上去 ...
是我的话就考虑做个架子,固定死9个水晶头和9个座子,只有最边上两个水晶头有背后的卡子,其余的全剪掉,一次性插9个头。拔的话也只需要按两个卡子。
提示: 作者被禁止或删除 内容自动屏蔽
高级工程师, 积分 5410, 距离下一级还需 2590 积分
高级工程师, 积分 5410, 距离下一级还需 2590 积分
高级工程师, 积分 5410, 距离下一级还需 2590 积分
高级工程师, 积分 5410, 距离下一级还需 2590 积分
这个办法我考虑过,就一般工厂的钻铣床和电木板,不太可能实现。故不提 ...
我笑而不语
初级工程师, 积分 2291, 距离下一级还需 709 积分
初级工程师, 积分 2291, 距离下一级还需 709 积分
初级工程师, 积分 2291, 距离下一级还需 709 积分
初级工程师, 积分 2291, 距离下一级还需 709 积分
有一种高速连接器的。走这么多个GE没有问题
提示: 作者被禁止或删除 内容自动屏蔽
高级工程师, 积分 5410, 距离下一级还需 2590 积分
高级工程师, 积分 5410, 距离下一级还需 2590 积分
高级工程师, 积分 5410, 距离下一级还需 2590 积分
高级工程师, 积分 5410, 距离下一级还需 2590 积分
你能做好这个冶具,那动手能力应该会比我和专业的ME更强。我96-97年先后做过修理工,PE,QE,QAE,跟ME打 ...
其实我不喜欢拿电路板**座,没自锁.
网线的水晶头是我目前碰到的即使是经常拔插也问题最少的接插件了,当然前提是头要好.
拼这种东西,做个模具什么的完全看手工,我农村出来的,老家几乎没什么条件,要什么样子的东西都只能拿刀子刻,我们那甚至连吸锡器都难找,经常只能用嘴吹.
9根千兆,意思就是要用完8芯,一共72芯,做在一起要不要考虑干扰我不能给答案.
目前碰到过能达到这个PIN数的金属接头:80PIN的SCSI,有两种,一种是全塑料的机内连线,一种是金属外壳的耐拔插线.
机内的不要用,要用机外的金属头的.
还有一个我见过,没用过,是电信给单位机房配备的光端机上的电话线接头,好像出来几十路电话信号.
能不能做成一个通9路千兆网络的接头我不知道.但我建议LZ要去找金属包边的接插件,塑料的用用就碰裂了.
扫描二维码,随时随地手机跟帖
时间类勋章
终身成就奖章
等级类勋章
坚毅之洋流
发帖类勋章
技术领袖奖章
人才类勋章
社区建设奖章
等级类勋章
欢快之小溪
发帖类勋章
时间类勋章
技术导师奖章
人才类勋章
荣誉元老奖章
等级类勋章
时间类勋章
涓涓之细流
发帖类勋章
技术高手奖章
人才类勋章
技术新星奖章
人才类勋章
时间类勋章
精华达人奖章
等级类勋章
您需要登录后才可以回帖
热门推荐 /4F429提供的接口有哪些_百度知道
F429提供的接口有哪些
我有更好的答案
CPU=&插CPU,多为矩形。内存=&插内存条,靠近CPU插座的长条形AGP=&插接显卡,连接显示器PCI=&多为白色长条,插其他的东西的。网卡,声卡什么的
采纳率:87%
为您推荐:
其他类似问题
换一换
回答问题,赢新手礼包
个人、企业类
违法有害信息,请在下方选择后提交
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。自己写库-构建库函数雏形—零死角玩转STM32-F429系列
时间: 12:46:19
&&&& 阅读:164
&&&& 评论:
&&&& 收藏:0
标签:第8章 ????自己写库—构建库函数雏形
全套集视频教程和页教程请到秉火论坛下载:野火视频教程优酷观看网址:
?本章参考资料:《中文参考手册》、《规格书》虽然我们上面用寄存器点亮了,乍看一下好像代码也很简单,但是我们别侥幸以后就可以一直用寄存器开发。在用寄存器点亮的时候,我们会发现的寄存器都是位的,每次配置的时候都要对照着《参考手册》中寄存器的说明,然后根据说明对每个控制的寄存器位写入特定参数,因此在配置的时候非常容易出错,而且代码还很不好理解,不便于维护。所以学习最好的方法是用软件库,然后在软件库的基础上了解底层,学习遍所有寄存器。8.1
什么是STM32函数库
以上所说的软件库是指"标准函数库",它是由公司针对提供的函数接口,即,开发者可调用这些函数接口来配置的寄存器,使开发人员得以脱离最底层的寄存器操作,有开发快速,易于阅读,维护成本低等优点。当我们调用库的时候不需要挖空心思去了解库底层的寄存器操作,就像当年我们刚开始学习语言的时候,用函数时只是学习它的使用格式,并没有去研究它的源码实现,但需要深入研究的时候,经过千锤百炼的库源码就是最佳学习范例。实际上,库是架设在寄存器与用户驱动层之间的代码,向下处理与寄存器直接相关的配置,向上为用户提供配置寄存器的接口。库开发方式与直接配置寄存器方式的区别见图。
图 81 开发方式对比图
为什么采用库来开发及学习?
在以前位机时代的程序开发中,一般直接配置芯片的寄存器,控制芯片的工作方式,如中断,定时器等。配置的时候,常常要查阅寄存器表,看用到哪些配置位,为了配置某功能,该置还是置。这些都是很琐碎的、机械的工作,因为位机的软件相对来说较简单,而且资源很有限,所以可以直接配置寄存器的方式来开发。对于,因为外设资源丰富,带来的必然是寄存器的数量和复杂度的增加,这时直接配置寄存器方式的缺陷就突显出来了:(1)????开发速度慢
(2)????程序可读性差
(3)????维护复杂
这些缺陷直接影响了开发效率,程序维护成本,交流成本。库开发方式则正好弥补了这些缺陷。而坚持采用直接配置寄存器的方式开发的程序员,会列举以下原因:(1)????具体参数更直观
(2)????程序运行占用资源少
相对于库开发的方式,直接配置寄存器方式生成的代码量的确会少一点,但因为有充足的资源,权衡库的优势与不足,绝大部分时候,我们愿意牺牲一点资源,选择库开发。一般只有在对代码运行时间要求极苛刻的地方,才用直接配置寄存器的方式代替,如频繁调用的中断服务函数。对于库开发与直接配置寄存器的方式,就好比编程是用汇编好还是用好一样。在系列刚推出函数库时引起程序员的激烈争论,但是,随着库的完善与大家对库的了解,更多的程序员选择了库开发。现在系列和系列各有一套自己的函数库,但是它们大部分是兼容的,和之间的程序移植,只需要小修改即可。而如果要移植用寄存器写的程序,我只想说:"呵呵"。用库来进行开发,市场已有定论,用户群说明了一切,但对于的学习仍然有人认为用寄存器好,而且汇编不是还没退出大学教材么?认为这种方法直观,能够了解到是配置了哪些寄存器,怎样配置寄存器。事实上,库函数的底层实现恰恰是直接配置寄存器方式的最佳例子,它代替我们完成了寄存器配置的工作,而想深入了解芯片是如何工作的话,只要直接查看库函数的最底层实现就能理解,相信你会为它严谨、优美的实现方式而陶醉,要想修炼语言,就从的库开始吧。所以在以后的章节中,使用软件库是我们的重点,而且我们通过讲解库去高效地学习的寄存器,并不至于因为用库学习,就不会用寄存器控制芯片。8.3
实验:构建库函数雏形
虽然库的优点多多,但很多人对库还是很忌惮,因为一开始用库的时候有很多代码,很多文件,不知道如何入手。不知道您是否认同这么一句话:一切的恐惧都来源于认知的空缺。我们对库忌惮那是因为我们不知道什么是库,不知道库是怎么实现的。接下来,我们在寄存器点亮的代码上继续完善,把代码一层层封装,实现库的最初的雏形,相信经过这一步的学习后,您对库的运用会游刃有余。这里我们只讲如何实现函数库,其他外设的我们直接参考标准库学习即可,不必自己写。下面请打开本章配套例程"构建库函数雏形"来阅读理解,该例程是在上一章的基础上修改得来的。8.3.1
修改寄存器地址封装
上一章中我们在操作寄存器的时候,操作的是都寄存器的绝对地址,如果每个外设寄存器都这样操作,那将非常麻烦。我们考虑到外设寄存器的地址都是基于外设基地址的偏移地址,都是在外设基地址上逐个连续递增的,每个寄存器占个或者个字节,这种方式跟结构体里面的成员类似。所以我们可以定义一种外设结构体,结构体的地址等于外设的基地址,结构体的成员等于寄存器,成员的排列顺序跟寄存器的顺序一样。这样我们操作寄存器的时候就不用每次都找到绝对地址,只要知道外设的基地址就可以操作外设的全部寄存器,即操作结构体的成员即可。在工程中的""文件中,我们使用结构体封装及外设的的寄存器,见代码清单。结构体成员的顺序按照寄存器的偏移地址从低到高排列,成员类型跟寄存器类型一样。如不理解语言对寄存器的封的语法原理,请参考语言对寄存器的封装》小节。代码清单 81 封装寄存器列表
1 //volatile表示易变的变量,防止编译器优化
unsigned int uint32_t;
unsigned short uint16_t;
6 /* GPIO寄存器列表 */
uint32_t MODER;
/*GPIO模式寄存器
地址偏移: 0x00
uint32_t OTYPER;
/*GPIO输出类型寄存器
地址偏移: 0x04
uint32_t OSPEEDR;
/*GPIO输出速度寄存器
地址偏移: 0x08
uint32_t PUPDR;
/*GPIO上拉/下拉寄存器
地址偏移: 0x0C
uint32_t IDR;
/*GPIO输入数据寄存器
地址偏移: 0x10
uint32_t ODR;
/*GPIO输出数据寄存器
地址偏移: 0x14
uint16_t BSRRL; /*GPIO置位/复位寄存器低16位部分
地址偏移: 0x18 */
uint16_t BSRRH; /*GPIO置位/复位寄存器
高16位部分地址偏移: 0x1A */
uint32_t LCKR;
/*GPIO配置锁定寄存器
地址偏移: 0x1C
uint32_t AFR[2];
/*GPIO复用功能配置寄存器
地址偏移: 0x20-0x24 */
18 } GPIO_TypeD
20 /*RCC寄存器列表*/
21 typedef
uint32_t CR;
/*!& RCC 时钟控制寄存器,地址偏移: 0x00 */
uint32_t PLLCFGR; /*!& RCC PLL配置寄存器,地址偏移: 0x04 */
uint32_t CFGR;
/*!& RCC 时钟配置寄存器,地址偏移: 0x08 */
uint32_t CIR;
/*!& RCC 时钟中断寄存器,地址偏移: 0x0C */
uint32_t AHB1RSTR; /*!& RCC AHB1 外设复位寄存器,地址偏移: 0x10 */
uint32_t AHB2RSTR; /*!& RCC AHB2 外设复位寄存器,地址偏移: 0x14 */
uint32_t AHB3RSTR; /*!& RCC AHB3 外设复位寄存器,地址偏移: 0x18 */
uint32_t RESERVED0; /*!& 保留, 地址偏移:0x1C */
uint32_t APB1RSTR; /*!& RCC APB1 外设复位寄存器,地址偏移: 0x20 */
uint32_t APB2RSTR;
/*!& RCC APB2 外设复位寄存器,地址偏移: 0x24*/
uint32_t RESERVED1[2];
/*!& 保留,地址偏移:0x28-0x2C*/
uint32_t AHB1ENR;
/*!& RCC AHB1 外设时钟寄存器,地址偏移: 0x30 */
uint32_t AHB2ENR;
/*!& RCC AHB2 外设时钟寄存器,地址偏移: 0x34 */
uint32_t AHB3ENR; /*!& RCC AHB3 外设时钟寄存器,地址偏移: 0x38 */
/*RCC后面还有很多寄存器,此处省略*/
37 } RCC_TypeD这段代码在每个结构体成员前增加了一个""前缀,它的原型在这段代码的第一行,代表了语言中的关键字"",在语言中该关键字用于表示变量是易变的,要求编译器不要优化。这些结构体内的成员,都代表着寄存器,而寄存器很多时候是由外设或芯片状态修改的,也就是说即使不执行代码修改这些变量,变量的值也有可能被外设修改、更新,所以每次使用这些变量的时候,我们都要求去该变量的地址重新访问。若没有这个关键字修饰,在某些情况下,编译器认为没有代码修改该变量,就直接从的某个缓存获取该变量值,这时可以加快执行速度,但该缓存中的是陈旧数据,与我们要求的寄存器最新状态可能会有出入。8.3.2
定义访问外设的结构体指针
以结构体的形式定义好了外设寄存器后,使用结构体前还需要给结构体的首地址赋值,才能访问到需要的寄存器。为方便操作,我们给每个外设都定义好指向它地址的结构体指针,见代码清单。代码清单 82 指向外设首地址的结构体指针
1 /*定义GPIOA-H 寄存器结构体指针*/
2 #define GPIOA
((GPIO_TypeDef *) GPIOA_BASE)
3 #define GPIOB
((GPIO_TypeDef *) GPIOB_BASE)
4 #define GPIOC
((GPIO_TypeDef *) GPIOC_BASE)
5 #define GPIOD
((GPIO_TypeDef *) GPIOD_BASE)
6 #define GPIOE
((GPIO_TypeDef *) GPIOE_BASE)
7 #define GPIOF
((GPIO_TypeDef *) GPIOF_BASE)
8 #define GPIOG
((GPIO_TypeDef *) GPIOG_BASE)
9 #define GPIOH
((GPIO_TypeDef *) GPIOH_BASE)
11 /*定义RCC外设
寄存器结构体指针*/
12 #define RCC
((RCC_TypeDef *) RCC_BASE)这些宏通过强制把外设的基地址转换成类型的地址,从而得到、等直接指向对应外设的指针,通过结构体的指针操作,即可访问对应外设的寄存器。利用这些指针访问寄存器,我们把文件里对应的代码修改掉,见代码清单。代码清单 83 使用结构体指针方式控制LED灯
4 int main(void)
RCC-&AHB1ENR |= (1&&7);
/* LED 端口初始化 */
/*GPIOH MODER10清空*/
GPIOH-&MODER
&= ~( 0x03&& (2*10));
/*PH10 MODER10 = 01b 输出模式*/
GPIOH-&MODER |= (1&&2*10);
/*GPIOH OTYPER10清空*/
GPIOH-&OTYPER &= ~(1&&1*10);
/*PH10 OTYPER10 = 0b 推挽模式*/
GPIOH-&OTYPER |= (0&&1*10);
/*GPIOH OSPEEDR10清空*/
GPIOH-&OSPEEDR &= ~(0x03&&2*10);
/*PH10 OSPEEDR10 = 0b 速率2MHz*/
GPIOH-&OSPEEDR |= (0&&2*10);
/*GPIOH PUPDR10清空*/
GPIOH-&PUPDR &= ~(0x03&&2*10);
/*PH10 PUPDR10 = 01b 上拉模式*/
GPIOH-&PUPDR |= (1&&2*10);
/*PH10 BSRR寄存器的 BR10置1,使引脚输出低电平*/
GPIOH-&BSRRH |= (1&&10);
/*PH10 BSRR寄存器的 BS10置1,使引脚输出高电平*/
//GPIOH-&BSRRL |= (1&&10);
while (1);
乍一看,除了最后一部分,把寄存器分成和两段,其它部分跟直接用绝对地址访问只是名字改了而已,用起来跟上一章没什么区别。这是因为我们现在只实现了库函数的基础,还没有定义库函数。打好了地基,下面我们就来建高楼。接下来使用函数来封装的基本操作,方便以后应用的时候不需要再查询寄存器,而是直接通过调用这里定义的函数来实现。我们把针对外设操作的函数及其宏定义分别存放在""和""文件中。定义位操作函数在""文件定义两个位操作函数,分别用于控制引脚输出高电平和低电平,见代码清单。代码清单 84 GPIO置位函数与复位函数的定义
*函数功能:设置引脚为高电平
*参数说明:GPIOx:该参数为GPIO_TypeDef类型的指针,指向GPIO端口的地址
GPIO_Pin:选择要设置的GPIO端口引脚,可输入宏GPIO_Pin_0-15,
表示GPIOx端口的0-15号引脚。
7 void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
/*设置GPIOx端口BSRRL寄存器的第GPIO_Pin位,使其输出高电平*/
/*因为BSRR寄存器写0不影响,
宏GPIO_Pin只是对应位为1,其它位均为0,所以可以直接赋值*/
GPIOx-&BSRRL = GPIO_P
*函数功能:设置引脚为低电平
*参数说明:GPIOx:该参数为GPIO_TypeDef类型的指针,指向GPIO端口的地址
GPIO_Pin:选择要设置的GPIO端口引脚,可输入宏GPIO_Pin_0-15,
表示GPIOx端口的0-15号引脚。
22 void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
/*设置GPIOx端口BSRRH寄存器的第GPIO_Pin位,使其输出低电平*/
/*因为BSRR寄存器写0不影响,
宏GPIO_Pin只是对应位为1,其它位均为0,所以可以直接赋值*/
GPIOx-&BSRRH = GPIO_P
这两个函数体内都是只有一个语句,对的或寄存器赋值,从而设置引脚为高电平或低电平。其中是一个指针变量,通过函数的输入参数我们可以修改它的值,如给它赋予、、等结构体指针值,这个函数就可以控制相应的、、等端口的输出。对比我们前面对寄存器的赋值,都是用""操作来防止对其它数据位产生干扰的,为何此函数里的操作却直接用""号赋值,这样不怕干扰其它数据位吗?见代码清单。代码清单 85 赋值方式对比
1 /*使用 "|=" 来赋值*/
2 GPIOH-&BSRRH |= (1&&10);
3 /*直接使用 "=" 号赋值*/
4 GPIOx-&BSRRH = GPIO_P根据寄存器的特性,对它的数据位写"",是不会影响输出的,只有对它的数据位写"",才会控制引脚输出。对低位写""输出高电平,对高位写""输出低电平。也就是说,假如我们对高位直接用""操作赋二进制值"",它会控制的引脚输出低电平,赋二进制值"",它会控制引脚输出低电平,而其它数据位由于是,所以不会受到干扰。同理,对低位直接赋值也是如此,数据位为的位输出高电平。代码清单中的两种方式赋值,功能相同。代码清单 86 BSRR寄存器赋值等效代码
1 /*使用 "|=" 来赋值*/
2 GPIOH-&BSRRH |= (uint16_t)(1&&10);
3 /*直接使用"=" 来赋值,二进制数(00 0000)*/
4 GPIOH-&BSRRH =
(uint16_t)(1&&10);这两行代码功能等效,都把的设置为,控制引脚输出低电平,且其它引脚状态不变。但第二个语句操作效率是比较高的,因为""号包含了读写操作,而""号只需要一个写操作。因此在定义位操作函数中我们使用后者。利用这两个位操作函数,就可以方便地操作各种的引脚电平了,控制各种端口引脚的范例见代码清单。代码清单 87 位操作函数使用范例
2 /*控制GPIOH的引脚10输出高电平*/
3 GPIO_SetBits(GPIOH,(uint16_t)(1&&10));
4 /*控制GPIOH的引脚10输出低电平*/
5 GPIO_ResetBits(GPIOH,(uint16_t)(1&&10));
7 /*控制GPIOH的引脚10、引脚11输出高电平,使用"|"同时控制多个引脚*/
8 GPIO_SetBits(GPIOH,(uint16_t)(1&&10)|(uint16_t)(1&&11));
9 /*控制GPIOH的引脚10、引脚11输出低电平*/
10 GPIO_ResetBits(GPIOH,(uint16_t)(1&&10)|(uint16_t)(1&&10));
12 /*控制GPIOA的引脚8输出高电平*/
13 GPIO_SetBits(GPIOA,(uint16_t)(1&&8));
14 /*控制GPIOB的引脚9输出低电平*/
15 GPIO_ResetBits(GPIOB,(uint16_t)(1&&9));使用以上函数输入参数,设置引脚号时,还是稍感不便,为此我们把表示个引脚的操作数都定义成宏,见代码清单。代码清单 88 选择引脚参数的宏
1 /*GPIO引脚号定义*/
2 #define GPIO_Pin_0
(uint16_t)0x0001)
/*!& 选择Pin0 (1&&0) */
3 #define GPIO_Pin_1
((uint16_t)0x0002)
/*!& 选择Pin1 (1&&1)*/
4 #define GPIO_Pin_2
((uint16_t)0x0004)
/*!& 选择Pin2 (1&&2)*/
5 #define GPIO_Pin_3
((uint16_t)0x0008)
/*!& 选择Pin3 (1&&3)*/
6 #define GPIO_Pin_4
((uint16_t)0x0010)
/*!& 选择Pin4 */
7 #define GPIO_Pin_5
((uint16_t)0x0020)
/*!& 选择Pin5 */
8 #define GPIO_Pin_6
((uint16_t)0x0040)
/*!& 选择Pin6 */
9 #define GPIO_Pin_7
((uint16_t)0x0080)
/*!& 选择Pin7 */
10 #define GPIO_Pin_8
((uint16_t)0x0100)
/*!& 选择Pin8 */
11 #define GPIO_Pin_9
((uint16_t)0x0200)
/*!& 选择Pin9 */
12 #define GPIO_Pin_10
((uint16_t)0x0400)
/*!& 选择Pin10 */
13 #define GPIO_Pin_11
((uint16_t)0x0800)
/*!& 选择Pin11 */
14 #define GPIO_Pin_12
((uint16_t)0x1000)
/*!& 选择Pin12 */
15 #define GPIO_Pin_13
((uint16_t)0x2000)
/*!& 选择Pin13 */
16 #define GPIO_Pin_14
((uint16_t)0x4000)
/*!& 选择Pin14 */
17 #define GPIO_Pin_15
((uint16_t)0x8000)
/*!& 选择Pin15 */
18 #define GPIO_Pin_All
((uint16_t)0xFFFF)
/*!& 选择全部引脚 */
这些宏代表的参数是某位置""其它位置""的数值,其中最后一个""是所有数据位都为"",所以用它可以一次控制设置整个端口的所有引脚。利用这些宏,的控制代码可改为代码清单。代码清单 89 使用位操作函数及宏控制GPIO
2 /*控制GPIOH的引脚10输出高电平*/
3 GPIO_SetBits(GPIOH,GPIO_Pin_10);
4 /*控制GPIOH的引脚10输出低电平*/
5 GPIO_ResetBits(GPIOH,GPIO_Pin_10);
7 /*控制GPIOH的引脚10、引脚11输出高电平,使用"|",同时控制多个引脚*/
8 GPIO_SetBits(GPIOH,GPIO_Pin_10|GPIO_Pin_11);
9 /*控制GPIOH的引脚10、引脚11输出低电平*/
10 GPIO_ResetBits(GPIOH,GPIO_Pin_10|GPIO_Pin_11);
11 /*控制GPIOH的所有输出低电平*/
12 GPIO_ResetBits(GPIOH,GPIO_Pin_ALL);
14 /*控制GPIOA的引脚8输出高电平*/
15 GPIO_SetBits(GPIOA,GPIO_Pin_8);
16 /*控制GPIOB的引脚9输出低电平*/
17 GPIO_ResetBits(GPIOB,GPIO_Pin_9);
使用以上代码控制,我们就不需要再看寄存器了,直接从函数名和输入参数就可以直观看出这个语句要实现什么操作。英文中表示"置位",即高电平,""表示"复位",即低电平8.3.3
定义初始化结构体GPIO_InitTypeDef
定义位操作函数后,控制输出电平的代码得到了简化,但在控制输出电平前还需要初始化引脚的各种模式,这部分代码涉及的寄存器有很多,我们希望初始化也能以如此简单的方法去实现。为此,我们先根据初始化时涉及到的初始化参数以结构体的形式封装起来,声明一个名为的结构体类型,见代码清单。代码清单 810 定义GPIO初始化结构体
1 typedef uint8_
* GPIO初始化结构体类型定义
uint32_t GPIO_P
/*!& 选择要配置的GPIO引脚
可输入 GPIO_Pin_ 定义的宏 */
uint8_t GPIO_M
/*!& 选择GPIO引脚的工作模式
可输入二进制值: 00 、01、 10、 11
表示输入/输出/复用/模拟 */
uint8_t GPIO_S
/*!& 选择GPIO引脚的速率
可输入二进制值: 00 、01、 10、 11
表示2/25/50/100MHz */
uint8_t GPIO_OT
/*!& 选择GPIO引脚输出类型
可输入二进制值: 0 、1
表示推挽/开漏 */
uint8_t GPIO_PuPd;
/*!&选择GPIO引脚的上/下拉模式
可输入二进制值: 00 、01、 10
表示浮空/上拉/下拉*/
24 } GPIO_InitTypeD
这个结构体中包含了初始化所需要的信息,包括引脚号、工作模式、输出速率、输出类型以及上下拉模式。设计这个结构体的思路是:初始化前,先定义一个这样的结构体变量,根据需要配置的模式,对这个结构体的各个成员进行赋值,然后把这个变量作为"初始化函数"的输入参数,该函数能根据这个变量值中的内容去配置寄存器,从而实现初始化。8.3.4
定义引脚模式的枚举类型
上面定义的结构体很直接,美中不足的是在对结构体中各个成员赋值时还需要看具体哪个模式对应哪个数值,如成员的"输入输出复用模拟"模式对应二进制值"、、、",我们不希望每次用到都要去查找这些索引值,所以使用语言中的枚举语法定义这些参数,见代码清单。代码清单 811 GPIO配置参数的枚举定义
* GPIO端口配置模式的枚举定义
GPIO_Mode_IN
= 0x00, /*!& 输入模式 */
GPIO_Mode_OUT
= 0x01, /*!& 输出模式 */
GPIO_Mode_AF
= 0x02, /*!& 复用模式 */
GPIO_Mode_AN
/*!& 模拟模式 */
9 } GPIOMode_TypeD
* GPIO输出类型枚举定义
14 typedef
GPIO_OType_PP = 0x00,
/*!& 推挽模式 */
GPIO_OType_OD = 0x01
/*!& 开漏模式 */
17 } GPIOOType_TypeD
* GPIO输出速率枚举定义
22 typedef
GPIO_Speed_2MHz
= 0x00, /*!& 2MHz
GPIO_Speed_25MHz
= 0x01, /*!& 25MHz
GPIO_Speed_50MHz
= 0x02, /*!& 50MHz
GPIO_Speed_100MHz = 0x03
/*!&100MHz
27 } GPIOSpeed_TypeD
*GPIO上/下拉配置枚举定义
32 typedef
GPIO_PuPd_NOPULL = 0x00,/*浮空*/
GPIO_PuPd_UP
= 0x01, /*上拉*/
GPIO_PuPd_DOWN
36 } GPIOPuPd_TypeD
有了这些枚举定义,我们的结构体也可以使用枚举类型来限定输入了,代码清单。代码清单 812 使用枚举类型定义的GPIO_InitTypeDef结构体成员
* GPIO初始化结构体类型定义
uint32_t GPIO_P
/*!& 选择要配置的GPIO引脚
可输入 GPIO_Pin_ 定义的宏 */
GPIOMode_TypeDef GPIO_M
/*!& 选择GPIO引脚的工作模式
可输入 GPIOMode_TypeDef 定义的枚举值*/
GPIOSpeed_TypeDef GPIO_S
/*!& 选择GPIO引脚的速率
可输入 GPIOSpeed_TypeDef 定义的枚举值 */
GPIOOType_TypeDef GPIO_OT
/*!& 选择GPIO引脚输出类型
可输入 GPIOOType_TypeDef 定义的枚举值*/
GPIOPuPd_TypeDef GPIO_PuPd;
/*!&选择GPIO引脚的上/下拉模式
可输入 GPIOPuPd_TypeDef 定义的枚举值*/
19 } GPIO_InitTypeD
如果不使用枚举类型,仍使用""类型来定义结构体成员,那么成员值的范围就是了,而实际上这些成员都只能输入几个数值。所以使用枚举类型可以对结构体成员起到限定输入的作用,只能输入相应已定义的枚举值。利用这些枚举定义,给结构体类型赋值配置就非常直观了,范例见代码清单。代码清单 813 给GPIO_InitTypeDef初始化结构体赋值范例
1 GPIO_InitTypeDef InitS
3 /* LED 端口初始化 */
4 /*选择要控制的GPIO引脚*/
5 InitStruct.GPIO_Pin = GPIO_Pin_10;
6 /*设置引脚模式为输出模式*/
7 InitStruct.GPIO_Mode = GPIO_Mode_OUT;
8 /*设置引脚的输出类型为推挽输出*/
9 InitStruct.GPIO_OType = GPIO_OType_PP;
10 /*设置引脚为上拉模式*/
11 InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
12 /*设置引脚速率为2MHz */
13 InitStruct.GPIO_Speed = GPIO_Speed_2MHz;
定义GPIO初始化函数
接着前面的思路,对初始化结构体赋值后,把它输入到初始化函数,由它来实现寄存器配置。我们的初始化函数实现见代码清单,代码清单 814 GPIO初始化函数
*函数功能:初始化引脚模式
*参数说明:GPIOx,该参数为GPIO_TypeDef类型的指针,指向GPIO端口的地址
GPIO_InitTypeDef:GPIO_InitTypeDef结构体指针,指向初始化变量
7 void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct)
uint32_t pinpos = 0x00, pos = 0x00 , currentpin = 0x00;
/*-- GPIO Mode Configuration --*/
for (pinpos = 0x00; pinpos & 16; pinpos++) {
/*以下运算是为了通过 GPIO_InitStruct-&GPIO_Pin 算出引脚号0-15*/
/*经过运算后pos的pinpos位为1,其余为0,与GPIO_Pin_x宏对应。
pinpos变量每次循环加1,*/
pos = ((uint32_t)0x01) &&
/* pos与GPIO_InitStruct-&GPIO_Pin做 & 运算,
若运算结果currentpin == pos,
则表示GPIO_InitStruct-&GPIO_Pin的pinpos位也为1,
从而可知pinpos就是GPIO_InitStruct-&GPIO_Pin对应的引脚号:0-15*/
currentpin = (GPIO_InitStruct-&GPIO_Pin) &
/*currentpin == pos时执行初始化*/
if (currentpin == pos) {
/*GPIOx端口,MODER寄存器的GPIO_InitStruct-&GPIO_Pin对应的引脚,
MODER位清空*/
GPIOx-&MODER
&= ~(3 && (2 *pinpos));
/*GPIOx端口,MODER寄存器的GPIO_Pin引脚,
MODER位设置"输入/输出/复用输出/模拟"模式*/
GPIOx-&MODER |= (((uint32_t)GPIO_InitStruct-&GPIO_Mode) && (2 *pinpos));
/*GPIOx端口,PUPDR寄存器的GPIO_Pin引脚,
PUPDR位清空*/
GPIOx-&PUPDR &= ~(3 && ((2 *pinpos)));
/*GPIOx端口,PUPDR寄存器的GPIO_Pin引脚,
PUPDR位设置"上/下拉"模式*/
GPIOx-&PUPDR |= (((uint32_t)GPIO_InitStruct-&GPIO_PuPd) && (2 *pinpos));
/*若模式为"输出/复用输出"模式,则设置速度与输出类型*/
if ((GPIO_InitStruct-&GPIO_Mode == GPIO_Mode_OUT) ||
(GPIO_InitStruct-&GPIO_Mode == GPIO_Mode_AF)) {
/*GPIOx端口,OSPEEDR寄存器的GPIO_Pin引脚,
OSPEEDR位清空*/
GPIOx-&OSPEEDR &= ~(3 && (2 *pinpos));
/*GPIOx端口,OSPEEDR寄存器的GPIO_Pin引脚,
OSPEEDR位设置输出速度*/
GPIOx-&OSPEEDR |= ((uint32_t)(GPIO_InitStruct-&GPIO_Speed)&&(2 *pinpos));
/*GPIOx端口,OTYPER寄存器的GPIO_Pin引脚,
OTYPER位清空*/
GPIOx-&OTYPER
&= ~(1 && (pinpos)) ;
/*GPIOx端口,OTYPER位寄存器的GPIO_Pin引脚,
OTYPER位设置"推挽/开漏"输出类型*/
GPIOx-&OTYPER |= (uint16_t)(( GPIO_InitStruct-&GPIO_OType)&& (pinpos));
这个函数有和两个输入参数,分别是外设指针和初始化结构体指针。分别用来指定要初始化的端口及引脚的工作模式。函数实现主要分两个环节:利用循环,根据的结构体成员计算出要初始化的引脚号。这段看起来复杂的运算实际上可以这样理解:它要通过宏""的参数计算出值宏的参数值是第数据位为,其余为,参考代码清单,计算得的引脚号结果存储在变量中。得到引脚号后,利用初始化结构体各个成员的值,对相应寄存器进行配置,这部分与我们前面直接配置寄存器的操作是类似的,先对引脚号相应的配置位清空,后根据结构体成员对配置位赋值成员对应寄存器的配置,成员对应寄存器的配置等。区别是这里的寄存器配置值及引脚号都是由变量存储的。8.3.6
全新面貌,使用函数点亮LED灯
完成以上的准备后,我们就可以自己定义的函数来点亮灯了,见代码清单。代码清单 815 使用函数点亮LED灯
使用寄存器的方法点亮LED灯
5 #include
"stm32f4xx_gpio.h"
7 void Delay( uint32_t nCount);
主函数,使用封装好的函数来控制LED灯
12 int main(void)
GPIO_InitTypeDef InitS
/*开启 GPIOH 时钟,使用外设时都要先开启它的时钟*/
RCC-&AHB1ENR |= (1&&7);
/* LED 端口初始化 */
/*初始化PH10引脚*/
/*选择要控制的GPIO引脚*/
InitStruct.GPIO_Pin = GPIO_Pin_10;
/*设置引脚模式为输出模式*/
InitStruct.GPIO_Mode = GPIO_Mode_OUT;
/*设置引脚的输出类型为推挽输出*/
InitStruct.GPIO_OType = GPIO_OType_PP;
/*设置引脚为上拉模式*/
InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
/*设置引脚速率为2MHz */
InitStruct.GPIO_Speed = GPIO_Speed_2MHz;
/*调用库函数,使用上面配置的GPIO_InitStructure初始化GPIO*/
GPIO_Init(GPIOH, &InitStruct);
/*使引脚输出低电平,点亮LED1*/
GPIO_ResetBits(GPIOH,GPIO_Pin_10);
/*延时一段时间*/
Delay(0xFFFFFF);
/*使引脚输出高电平,关闭LED1*/
GPIO_SetBits(GPIOH,GPIO_Pin_10);
/*初始化PH11引脚*/
InitStruct.GPIO_Pin = GPIO_Pin_11;
GPIO_Init(GPIOH,&InitStruct);
/*使引脚输出低电平,点亮LED2*/
GPIO_ResetBits(GPIOH,GPIO_Pin_11);
while (1);
55 //简单的延时函数,让cpu执行无意义指令,消耗时间
56 //具体延时时间难以计算,以后我们可使用定时器精确延时
57 void Delay( uint32_t nCount)
for (; nCount != 0; nCount--);
62 // 函数为空,目的是为了骗过编译器不报错
63 void SystemInit(void)
现在看起来,使用函数来控制灯与之前直接控制寄存器已经有了很大的区别:函数中先定义了一个初始化结构体变量,然后对该变量的各个成员按点亮灯所需要的配置模式进行赋值,赋值后,调用函数,让它根据结构体成员值对寄存器写入控制参数,完成引脚初始化。控制电平时,直接使用和函数控制输出。如若对其它引脚进行不同模式的初始化,只要修改初始化结构体的成员值,把新的参数值输入到函数再调用即可。代码中新增的函数,主要功能是延时,让我们可以看清楚实验现象不延时的话指令执行太快,肉眼看不出来,它的实现原理是让执行无意义的指令,消耗时间,在此不要纠结它的延时时间,写一个大概输入参数值,下载到实验板实测,觉得太久了就把参数值改小,短了就改大即可。需要精确延时的时候我们会用的定时器外设进行精确延时的。8.3.7
把编译好的程序下载到开发板并复位,可看到板子上的灯先亮红色,后亮绿色。8.3.8
什么是标准软件库?这就是。我们从寄存器映像开始,把内存跟寄存器建立起一一对应的关系,然后操作寄存器点亮,再把寄存器操作封装成一个个函数。一步一步走来,我们实现了库最简单的雏形,如果我们不断地增加操作外设的函数,并且把所有的外设都写完,一个完整的库就实现了。本章中的相关库函数及结构体定义,实际上都是从标准库搬过来的。这样分析它纯粹是为了满足自己的求知欲,学习其编程的方式、思想,这对提高我们的编程水平是很有好处的,顺便感受一下库设计的严谨性,我认为这样的代码不仅严谨且华丽优美,不知您是否也有这样的感受。与直接配置寄存器相比,从执行效率上看会有额外的消耗:初始化变量赋值的过程、库函数在被调用的时候要耗费调用时间;在函数内部,对输入参数转换所需要的额外运算也消耗一些时间如中运算求出引脚号时。而其它的宏、枚举等解释操作是作编译过程完成的,这部分并不消耗内核的时间。那么函数库的优点呢?是我们可以快速上手控制器;配置外设状态时,不需要再纠结要向寄存器写入什么数值;交流方便,查错简单。这就是我们选择库的原因。现在的处理器的主频是越来越高,我们不需要担心耗费那么多时间来干活会不会被累倒,库主要应用是在初始化过程,而初始化过程一般是芯片刚上电或在核心运算之前的执行的,这段时间的等待是还是在很多时候并没有什么区别。相对来说,我们还是担心一下如果都用寄存器操作,每行代码都要查《规格书》中的说明,自己会不会被累倒吧。在以后开发的工程中,一般不会去分析的库函数的实现了。因为外设的库函数是很类似的,库外设都包含初始化结构体,以及特定的宏或枚举标识符,这些封装被库函数这些转化成相应的值,写入到寄存器之中,函数内部的具体实现是十分枯燥和机械的工作。如果您有兴趣,在您掌握了如何使用外设的库函数之后,可以查看一下它的源码实现。通常我们只需要通过了解每种外设的"初始化结构体"就能够通过它去了解的外设功能及控制了。8.4
1.????阅读《STM32F4xx参考手册》及《STM32F4xx规格书》中关于USART外设(通用同步异步收发器)的寄存器说明及地址映射,参考"GPIO_TypeDef"的结构体声明,封装USART的寄存器成一个USART_TypeDef类型,并定义USART1、USART2、USART3外设的结构体访问指针。
2.????参考GPIO_SetBits的函数实现,定义一个能读取GPIO引脚状态的函数,函数声明:"uint8_t
GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t
GPIO_Pin)",要求能够返回输入参数GPIOx端口的 GPIO_Pin引脚的电平状态,高电平时返回1,低电平返回0。
标签:原文地址:http://www.cnblogs.com/firege/p/5748511.html
&&国之画&&&& &&&&chrome插件&&
版权所有 京ICP备号-2
迷上了代码!}

我要回帖

更多关于 提供api接口的摄像头 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信