如何对单片机c语言编程300例IO口编程详解

 上传我的文档
 下载
 收藏
粉丝量:81
该文档贡献者很忙,什么也没留下。
 下载此文档
51单片机IO口图解
下载积分:840
内容提示:51单片机IO口图解
文档格式:PDF|
浏览次数:265|
上传日期: 16:38:47|
文档星级:
全文阅读已结束,如果下载本文需要使用
 840 积分
下载此文档
该用户还上传了这些文档
51单片机IO口图解
关注微信公众号后使用快捷导航没有帐号?
请完成以下验证码
查看: 9802|回复: 28
一起讨论:如何做一个单片机程序通用模版
在线时间1710 小时
威望24029分
芯币14839枚
TA的帖子TA的资源
随着一年多的真实产品开发——虽然,嘿嘿,按照他们的说法,我这实在有点非主流,但在后期的调试中吃了不少苦头,于是在蛋疼的调试中,以及在阅读诸如《代码大全》这些书籍时,渐渐地萌生了一种如何做一个方便调试,方便扩展,方便移植的单片机程序模板。而我,目前是渐渐地把它用在我自己的一个个人项目,一个用stm8的项目上,实际上,对这个模板的认识,最初只是有一种模糊的看法,渐渐的渐渐的,理论越来越清晰,但是,还需要在实际操作中得到完善和补充——比如之前对于io口的抽象,我一直简单的以为一个宏定义就可以解决,但如果不是到前天晚上 sjl 的那个问题,我也没有想到这个问题没有我想的那么简单,虽然后来我还是很快想到了办法解决。所以,这只是一个开放讨论的帖子,把我的一些想法,以及我已经在做的部分代码贴出来,希望大家一起讨论讨论,给点建议,或者评论评论,只希望,我,还有大家,能够在共同讨论中,找到一种也许更好的方式去写我们的单片机程序。(这里插一句题外话:事实上,我从来没有特别把单片机编程和一般意义上的编程分离开来,在我看来他们是一回事,并且也应该尝试使用一般意义上编程的一些成熟经典,方法,理论,来改善,来构建高质量的代码。)--------------------------------------------------------------------------------------------------------------------------------------------------首先解释一下,这个所谓的 单片机程序通用模板,我对它的定义,目前可以用以下特征来界定:1.它是通过恰当的分层,使其应用层和硬件底层抽离开来,这样做的目的,主要是 实现 不同MCU可以用最少的改动来实现移植,并保持良好兼容性。2.它是容易增删模块的,按照我个人的看法,单片机的功能模块,自然是以外设为单位来划分比较合适。&& ——注意,在这里,IO口也算是一种外设,当然,利用IO口去点亮LED,数码管或者读按键,这个和IO口的设置初始化是两回事。因为IO口设置和初始化可以为很多事情服务,点亮LED和读键只是其中一个功能。--------------------------这个界定还不算很完整,但它的确是我目前主要考虑的----------------------------------对于这个模板,我最先考虑的是利用分层和抽象的思想,实现第一个目标。现在先来说说这个基本思路,纸上谈谈兵先~~1.任何一个单片机程序都会包含两大层,一个是硬件底层的操作,比如操作相应寄存器,去打开某些外设,通过外设获取外部信息,或者影响外部。另一个则是 上层应用层,比如说,我要对通过单总线读来的温度值进行存储,显示。这两个层是单片机程序的最顶层 和 最底层。最顶层,往往只是一个 main函数,当然还包括其他中断子函数,它们就像一个一个独立的线程,和main是可能并行处理的。最底层,对于玩51的时候,可能没有这个概念,因为我们都是直接操作寄存器的。但是如果接触过其他单片机,特别是st系列的,了解过它那个固件库的必然就会知道我说的正是这个东西。stm8/32都有一个架构上几乎一模一样的固件库——我想,很多人也许和我一样,最初的编程规范习惯,以及之所以会产生这种分层思想,就是因为受到这个固件库的启发。这个最底层的目的是,使我们不需要直接面对寄存器,而是以外设为单元,方便使用。假如有一天,我们需要在51上或者其他MCU上也使用这个思想,我们也可以参照这种分类,来自行写一个属于我们的给51的,给430的固件库。对于我们熟悉的51,我相信这实在是一个简单不过的事情。在最底层 和 最高层之间,按照我的理解,还需要做两个层。我们叫做第二层 和 第三层,最高层为第一层,最底层为第四层。第二层就是我们的功能模块能,它都包含一些什么东西呢?它包含我们需要操作的外设,比如说 ds18b20啊,比如说数码管显示啊,比如说读键啊.....等等,因为,我们把所有这些都定义为 外设。如果对比st的固件库,也许你会认为我多此一举,不,是多此两举。第一,为什么要把外设的操作脱离寄存器那个层次的硬件底层?第二,就算是把外设单独出去吧,那为什么还有一层呢?不可以直接在 第四层基础上,建立一个外设层么——就好像,把st现有的固件库里,把那些很基本的gpio啊,exti啊等这些辅助性的更一般的,通用的部分 和 什么 iic 啊 spi啊之类的外设分离就好了。之所以这么做,我的考虑在于:1.我这个模板并不只是给stm8或者stm32使用,我是希望它可以与MCU无关;&& 所以,在st提供的固件库,可以操作gpio啊iic等固件库的基础上,我希望增加一个 硬件抽象层,这一层,它可以通过一个宏选择到对应具体不同MCU的那个第四层硬件底层API函数。&& 举个简单的例子,还是以st固件库为例。&&& 对于gpio的操作,通常由 设置方向 和 读写两个方向。&&& 这些操作st的固件库里都有,但是,现在,为了兼容不同的MCU,我要在第三层这个抽离层,再次封装一个gpio的 设置方向函数,读函数,写函数,而它将会通过一个宏,来选择st固件库里相应的操作函数。以我写的一段代码为例:#define STM8S/*这个宏是用于选择stm8s,这个取决于你的这个程序将使用在哪一个MCU上*/#include "gpio.h"/*gpio.h中的内容/*
For distinguish different MCU.
1.Here will be used a Macro to choose different GPIO hardware
headfile.*/#ifndef _GPIO_#define _GPIO_#ifdef STM8S#include "stm8s_gpio.h"#include "datastruct.h"/* Typedef Data-struct for compation */typedef GPIO_TypeDef GPIO_PORT;typedef GPIO_Pin_TypeDef GPIO_PIN;typedef GPIO_Mode_TypeDef GPIO_MODE;typedef BitStatus GPIO_BIT;/*
I/O mode & direction
In-Mode,concern two types:
1.Float Input(FL)
2.Pull-up(PU)
Interrupt w
Out-Mode,no care about speed,concern two types:
2.Push-Pull(PP)
default set the IO state to LOW,and no care about speed,as STM8 MCU can be set
different speed for GPIOs.*/#define IN_FL GPIO_MODE_IN_FL_NO_IT#define IN_PU GPIO_MODE_IN_PU_NO_IT
#define OUT_OD GPIO_MODE_OUT_OD_LOW_FAST#define OUT_PP GPIO_MODE_OUT_PP_LOW_FAST /*Basic Operation on IO,Include:
1. Set 1,Set 0;
All above two,include operation on bit & port*//* Function declaration */void Set_GPIO_Mode(GPIO_PORT* GPIOx, GPIO_PIN GPIO_Pin,GPIO_MODE mode);void Set_Port_Mode(GPIO_PORT* GPIOx,GPIO_MODE PortMode[8]);void Write_Port(GPIO_PORT* GPIOx,uint8_t PortValue);void Write_Pin_High(GPIO_PORT* GPIOx, GPIO_PIN GPIO_Pin);void Write_Pin_Low(GPIO_PORT* GPIOx, GPIO_PIN GPIO_Pin);uint8_t Read_Port(GPIO_PORT* GPIOx);GPIO_BIT Read_Pin(GPIO_PORT* GPIOx,GPIO_PIN GPIO_Pin);#endif#endif*/void Set_GPIO_Mode(GPIO_PORT* GPIOx, GPIO_PIN GPIO_Pin,GPIO_MODE mode){
GPIO_Init(GPIOx, GPIO_Pin, mode);}void Set_Port_Mode(GPIO_PORT* GPIOx,GPIO_MODE PortMode[8]){
GPIO_PIN PinMask[8] = {
GPIO_PIN_0,GPIO_PIN_1,GPIO_PIN_2,GPIO_PIN_3,
GPIO_PIN_4,GPIO_PIN_5,GPIO_PIN_6,GPIO_PIN_7,
for(i = 0;i & 8;i++)
Set_GPIO_Mode(GPIOx,PinMask[i],PortMode[i]);}//---------------------------------------------------------------------void Write_Port(GPIO_PORT* GPIOx,U8 PortValue){
GPIO_Write(GPIOx, PortValue);}void Write_Pin_High(GPIO_PORT* GPIOx, GPIO_PIN GPIO_Pin){
GPIO_WriteHigh(GPIOx, GPIO_Pin);}void Write_Pin_Low(GPIO_PORT* GPIOx, GPIO_PIN GPIO_Pin){
GPIO_WriteLow(GPIOx, GPIO_Pin);}//-----------------------------------------------------------------------U8 Read_Port(GPIO_PORT* GPIOx){
return GPIO_ReadInputData(GPIOx);}GPIO_BIT Read_Pin(GPIO_PORT* GPIOx,GPIO_PIN GPIO_Pin){
return GPIO_ReadInputPin(GPIOx, GPIO_Pin);}复制代码这是一份对应于stm8s的抽象层gpio源文件。我们可以以此为例子,写出针对于另一个平台的抽象层gpio.c但是,这里要遵循一个原则:那就是,所有的这些源文件里的函数,必须是同名。比如说,不管是51的还是430的抑或stm8,设置IO方向的,永远叫 Set_Gpio_Direction(.....)它们唯一的区别,只是在不同的宏条件下,实际的函数实现内容是不一样的。这种同名不同内容,正是实现MCU抽象的核心方法所在。BTW:当然,刚刚我突然想,反正这个第三层抽离层,针对不同MCU都不一样,那还不如直接跳过第四层,直接把固件库里对寄存器的操作直接复制过来,把第四层去掉好了。我觉得这也是不错的并且更直接的方法,我最开始总认为要第四层,那纯粹是因为受 st提供了一个固件库的影响所致。太长了,先发表,,接下来的内容,,回复里待续~~~
没有一件事情是容易的,所以,起念头时,一定要好好琢磨
在线时间244 小时
威望1992分
TA的帖子TA的资源
纯净的硅(高级), 积分 1992, 距离下一级还需 8 积分
纯净的硅(高级), 积分 1992, 距离下一级还需 8 积分
唉,眼睛累,看不下了……
在线时间1710 小时
威望24029分
芯币14839枚
TA的帖子TA的资源
第二层 模块抽象层
补充一句。
经过了第三层的 硬件抽象层以后,我们再向上时,我们操作任何东西,都不希望见到,或者说会屏蔽掉具体的硬件信息,比如说,在第二层及其以上,我们绝对不会直接操作P0 P1,GPIOA GPIOB,它们将通过 第二层的头文件定义,从这一层开始向上屏蔽。包括第二层自身的操作函数,也将见不到这类名字。&第二层 这一层是以模块为单位抽离的。我们要分清楚,模块的定义是什么?比方说,ds18b20肯定算一个模块,这个你肯定不会怀疑,那么,gpio算不算一个模块呢?这个问题也许很奇怪,也许你会说,当然算啊,你第三层不是就以gpio为例子实现的 硬件抽象 么?这里,要区分,那个硬件抽象 只是对gpio的基本操作,但是,并不代表,所有需要gpio来完成的功能,就属于那个抽象层。比方说,我要用gpio来显示数码管,那数码管就是一个 模块,其实说白了,ds18b20也是用一个gpio来实现单线读写的。所以,这里一定要区分清楚。但有一个问题比较复杂。那就是,对于一些硬件抽象层次的 模块该如何处理。举个例子,在51里,我们没有硬件的 iic spi等外设——这里说的是 标准8051,不包括那些增强型。而stm8s却一个不缺。这个时候,如果我们把它归入 第三层 硬件抽象层,那以后,遇到51,或者那个MCU并不存在硬件上的数字接口,需要软件模拟的那该怎么办呢?很明显,不能归入第三层,因为第三层是对 硬件 的抽象,但这种数字接口本身不属于 硬件必备,它不如gpio这样必不可确。那我们就归到第二层吧?也不行,为什么呢?第二层本来经过第三层隔离,它已经不再需要处理和相关硬件相关的信息,如果我们现在遇到一个硬件上存在数字接口的MCU,那我们势必要为此改动这个 第二层,但在我们的原则上,它是不应该因为换MCU而更换的。在这里,我最终会选择,把它归为 第三层,尽管,它实际上,并不是实际存在的硬件,而是软件模拟,但是软件模拟所需的硬件底层信息已经在第三层同层的其他函数里包含了。而向上,它就如同一个真实存在的硬件一般,这样,至少我可以保证,第二层是无需更改的。这一部分,我只能给出 一个 我写的 segment源文件,它是 动态扫描数码管(不通过IO扩展方式的),至于 前面更多篇幅讨论的数字接口部分,由于我还没有做到,所以,嘿嘿,暂时给不了了,只能纸上谈兵了。下面贴segment的代码,之前合在一起发有点乱,这次,头文件和源文件分两个发,更清楚。#ifdef STM8S#ifndef _SEG_#define _SEG_#include "stm8s.h"#include "gpio.h"#include "datastruct.h"#define MAX_SEG 11/**/#define Seg_Bit_Enable
Hardware pin define
bit_control
seg_control
e -----------
g left--&right
connecting:
seg_control: PB
bit_control:
4:PD6*/#define Seg_Bit_Port GPIOD#define Seg_Bit_1 GPIO_PIN_7#define Seg_Bit_2 GPIO_PIN_5#define Seg_Bit_3 GPIO_PIN_3#define Seg_Bit_4 GPIO_PIN_6#define Seg_Dig_Port GPIOBvoid Segment_IO_Initial(void);void Segment_Show(GPIO_PORT *SegPort,GPIO_PIN SegNum,U8 value);void Segment_Not_Show(GPIO_PORT *SegPort,GPIO_PIN SegNum,U8 value);void Segment_demo(void);void Segment_Bit_Enable(GPIO_PORT* Port,GPIO_PIN Pin);void Segment_Show_Value(GPIO_PORT* Port,U8 value);#endif#endif复制代码#define STM8S#include "segment.h"/* Segment code*//*
abcdefg dp --- bit 0~7
0xc0 0xf9 0xa4 0xb0 0x99 0x92 0x82 0xf8 0x80 0x90
if showdrop.
minus 0x80
0x40 0x79 0x24 0x30 0x11 0x12 0x02 0x78 0x00 0x10*/const U8 SegCode[MAX_SEG] = {
0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,
};void Segment_IO_Initial(void){
Set_GPIO_Mode(Seg_Dig_Port, GPIO_PIN_0,OUT_OD);
Set_GPIO_Mode(Seg_Dig_Port, GPIO_PIN_1,OUT_OD);
Set_GPIO_Mode(Seg_Dig_Port, GPIO_PIN_2,OUT_OD);
Set_GPIO_Mode(Seg_Dig_Port, GPIO_PIN_3,OUT_OD);
Set_GPIO_Mode(Seg_Dig_Port, GPIO_PIN_4,OUT_OD);
Set_GPIO_Mode(Seg_Dig_Port, GPIO_PIN_5,OUT_OD);
Set_GPIO_Mode(Seg_Dig_Port, GPIO_PIN_6,OUT_OD);
Set_GPIO_Mode(Seg_Dig_Port, GPIO_PIN_7,OUT_OD);
Set_GPIO_Mode(Seg_Bit_Port, Seg_Bit_1, OUT_OD);
Set_GPIO_Mode(Seg_Bit_Port, Seg_Bit_2, OUT_OD);
Set_GPIO_Mode(Seg_Bit_Port, Seg_Bit_3, OUT_OD);
Set_GPIO_Mode(Seg_Bit_Port, Seg_Bit_4, OUT_OD);}void Segment_Show(GPIO_TypeDef *SegPort,GPIO_Pin_TypeDef SegNum,uint8_t value){
Write_Pin_Low(Seg_Bit_Port,SegNum);} void Segment_Not_Show(GPIO_TypeDef *SegPort,GPIO_Pin_TypeDef SegNum,uint8_t value){
Write_Pin_High(Seg_Bit_Port,SegNum);} void Segment_demo(void){
Segment_Show(Seg_Bit_Port,Seg_Bit_1,0);
Segment_Show(Seg_Bit_Port,Seg_Bit_2,0);
Segment_Show(Seg_Bit_Port,Seg_Bit_3,0);
Segment_Not_Show(Seg_Bit_Port,Seg_Bit_4,0);}void Segment_Bit_Enable(GPIO_PORT* Port,GPIO_PIN Pin){
Segment_Show(Port,Pin,0);}void Segment_Show_Value(GPIO_PORT* Port,U8 value){
Write_Port(Port,value);}复制代码
[ 本帖最后由 辛昕 于
00:40 编辑 ]
没有一件事情是容易的,所以,起念头时,一定要好好琢磨
在线时间1710 小时
威望24029分
芯币14839枚
TA的帖子TA的资源
上面这个对于gpio引脚的处理,并不成熟,因为实际上,很可能他们的port口和pin脚都是乱的。
所以这种处理只适用于还是比较规律的IO连接,如果要实现任意连接,还得使用类似于我在 代码大全那个贴子里 给sjl回复里写的那段代码的方法。
通过一个算式,求出所属端口号 和 引脚数。
没有一件事情是容易的,所以,起念头时,一定要好好琢磨
在线时间2440 小时
威望3547分
芯币27054枚
E金币395枚
TA的帖子TA的资源
五彩晶圆(中级), 积分 3547, 距离下一级还需 2453 积分
五彩晶圆(中级), 积分 3547, 距离下一级还需 2453 积分
通用模板,最简单的处理就是写一些宏定义,包括常用的转化和算法。
再深一点,就是写个类似于M3上面的库。然后移植神马的都很方便。对于430,我是看到过个人有把各种外设写成“库”的,还有周立功公司,也写了很多库,类似于SD卡软件包,IP软件包,flash软件包等等,还有在TI的库上拓展M3的库,让更实用。
如果还要深入,就像这次hanker试用一样。triton.zhang把TI的库由外设包,延伸到了板级支持包,然后在头文件里修改参数就能很好的移植,做成开源,不断完善,再这个基础上再来开发M3/M4就更高效了。
在线时间2440 小时
威望3547分
芯币27054枚
E金币395枚
TA的帖子TA的资源
五彩晶圆(中级), 积分 3547, 距离下一级还需 2453 积分
五彩晶圆(中级), 积分 3547, 距离下一级还需 2453 积分
周立功公司的流明库里,有个芯片级的头文件,他把M3每个型号的GPIO的引脚的全部揉进去了,编程的时候都不需要管引脚了,直接宏一个芯片,就处理好了
在线时间3668 小时
威望5171分
芯币12574枚
E金币387枚
TA的帖子TA的资源
专业一点的叫法是 HAL-硬件抽象层
生活就是油盐酱醋再加一点糖,快活就是一天到晚乐呵呵的忙
===================================
做一个简单的人,踏实而务实,不沉溺幻想,不庸人自扰
在线时间2120 小时
威望8444分
芯币11554枚
E金币106枚
TA的帖子TA的资源
五彩晶圆(高级), 积分 8444, 距离下一级还需 1556 积分
五彩晶圆(高级), 积分 8444, 距离下一级还需 1556 积分
周立功制作的库的模板的确很不错 值得学习
在线时间1710 小时
威望24029分
芯币14839枚
TA的帖子TA的资源
回复 5楼 zca123 的帖子
都给个链接或者分享分享呗。
不过M3没碰过就是
430倒有开发板在手上
没有一件事情是容易的,所以,起念头时,一定要好好琢磨
在线时间2440 小时
威望3547分
芯币27054枚
E金币395枚
TA的帖子TA的资源
五彩晶圆(中级), 积分 3547, 距离下一级还需 2453 积分
五彩晶圆(中级), 积分 3547, 距离下一级还需 2453 积分
回复 8楼 辛昕 的帖子
M3的库,每家公司的都不一样。比如stellaris库
在线时间2440 小时
威望3547分
芯币27054枚
E金币395枚
TA的帖子TA的资源
五彩晶圆(中级), 积分 3547, 距离下一级还需 2453 积分
五彩晶圆(中级), 积分 3547, 距离下一级还需 2453 积分
原帖由 zca123 于
10:43 发表
周立功公司的流明库里,有个芯片级的头文件,他把M3每个型号的GPIO的引脚的全部揉进去了,编程的时候都不需要管引脚了,直接宏一个芯片,就处理好了
原来是周立功公司自己做,现在TI的官方库也有了这个文件pin_map.h
在线时间111 小时
TA的帖子TA的资源
一粒金砂(中级), 积分 22, 距离下一级还需 178 积分
一粒金砂(中级), 积分 22, 距离下一级还需 178 积分
作为初学者很感谢楼主的分享,有没有具体的库和其他的文件分享啊
在线时间1710 小时
威望24029分
芯币14839枚
TA的帖子TA的资源
回复 11楼 liujun 的帖子
正在编写中......
不过听他们说,有个周立功的库
没有一件事情是容易的,所以,起念头时,一定要好好琢磨
在线时间1710 小时
威望24029分
芯币14839枚
TA的帖子TA的资源
回复 10楼 zca123 的帖子
那么,你的意思是,直接到TI的那个对应的片子的页面去找咯?
额,TI的,我找过omap3,这个经历比较悲催,没找到啥有用的。
不过stm8的,我找st官网倒是比较成功
没有一件事情是容易的,所以,起念头时,一定要好好琢磨
在线时间335 小时
芯币1453枚
TA的帖子TA的资源
一粒金砂(高级), 积分 496, 距离下一级还需 4 积分
一粒金砂(高级), 积分 496, 距离下一级还需 4 积分
我也觉得这个很有必要,减少了很多的移植工作,尤其是在移植的时候出现问题还得调试。给LZ推荐一个网站,苏州大学的嵌入式实验室,有个 王宜怀 老师,搞 飞思卡尔的M4,K系列的单片机,他出来一个库,用的就是通用性的这个思想,LZ可以看看,借鉴一下。
在线时间1710 小时
威望24029分
芯币14839枚
TA的帖子TA的资源
回复 14楼 upc_arm 的帖子
没有一件事情是容易的,所以,起念头时,一定要好好琢磨
在线时间219 小时
威望2599分
芯币1233枚
TA的帖子TA的资源
五彩晶圆(初级), 积分 2599, 距离下一级还需 901 积分
五彩晶圆(初级), 积分 2599, 距离下一级还需 901 积分
回复 14楼 upc_arm 的帖子
估计是用K60的苦逼的孩子吧。。。。
在线时间1710 小时
威望24029分
芯币14839枚
TA的帖子TA的资源
分享一下下载到的 王宜怀老师 的 M4的一本书
听了 楼上的哥们的介绍,我搜索了一下 这位 王宜怀老师 的资料。
好几本都是书的介绍,还有一篇王宜怀老师 写的 嵌入式学习的误区和方法。
都是说的实实在在的话,而且其中也有我非常关心的几个信息点:
用 一般编程 的 方法和思想,不要把 单片机程序 看成独特的存在,不要电子化它,也不要软件化它.......
他也强调了 把程序写好,封装好,以便成为库方便调用的思想,所以,尽管我刚下载到这本书,还没开始看,但我有理由相信,至少,在他的程序里,不会出现
用while,甚至是 不同时间延迟都可以封装成不同子函数(这是我看过的好几本书上做ds18b20时所用的方法)——那种方法,我只是还在学校时用过两回,现在不会再用,以后也不会再用,因为我曾跟别人说过:
这样的程序,只有在教科书上才会看到,不然再快的MCU,遇到这种写法,都会傻得不成样子......
废话不多说了,这两天,花了很多精力在写这两个帖子(另一个是 代码大全),也时刻关心回复,果不负望,抛出去的砖真的引来了不少 美玉,可以让我有更多参考和学习。
谢谢大家。
晚上看了好一会的王宜怀老师的搜索页,心想总不能啥都不做,于是,找到这本M4的教程,居然有pdf下载,于是下载了,分享到这里~~希望对大家有帮助~~
[ 本帖最后由 辛昕 于
00:28 编辑 ]
00:28 上传
点击文件名下载附件
3.88 MB, 下载次数: 518
没有一件事情是容易的,所以,起念头时,一定要好好琢磨
在线时间1329 小时
威望4842分
芯币4211枚
TA的帖子TA的资源
五彩晶圆(中级), 积分 4842, 距离下一级还需 1158 积分
五彩晶圆(中级), 积分 4842, 距离下一级还需 1158 积分
msp430也有库的呀,其他的还有BSL呢
[ 本帖最后由 lyzhangxiang 于
12:58 编辑 ]
在线时间1329 小时
威望4842分
芯币4211枚
TA的帖子TA的资源
五彩晶圆(中级), 积分 4842, 距离下一级还需 1158 积分
五彩晶圆(中级), 积分 4842, 距离下一级还需 1158 积分
给楼主参考
13:00 上传
点击文件名下载附件
334.53 KB, 下载次数: 54
msp430库用户指南
13:00 上传
点击文件名下载附件
1.79 MB, 下载次数: 35
13:00 上传
点击文件名下载附件
494.01 KB, 下载次数: 40
MSP430驱动库
在线时间50 小时
TA的帖子TA的资源
一粒金砂(中级), 积分 170, 距离下一级还需 30 积分
一粒金砂(中级), 积分 170, 距离下一级还需 30 积分
学习了 很好
论坛测评队员
EEWORLD 官方微信
Powered by查看: 336|回复: 0
如何对单片机IO口编程详解
学习嵌入式还是先了解IO口吧,IO口作为单片机的基本单元作用很大
相关知识讲解:IO 口能做什么呢? IO 口是单片机中最基本的单元了,通过对 IO 口寄存器的控制, 可以让它作为输出管脚或者是输入管脚。作为输出管脚时,可以输出高电平(5V)或者是 低电平(0V),这个通过给数据寄存器赋值实现。作为输入脚时,可以检测到外部电平变化。在芯片手册中我们可以看到,对 IO 口的操作主要由两个寄存器实现,一个是数据方 向寄存器 DDR*(*代表 A、B、C…),一个是数据寄存器PORT*。以 DDRA 为例,我们可以看到一个寄存器,控制 8 个 IO 管脚,当相应位置 1 时,相 应管脚被配置成输出模式,当置 0 时,相应管脚被配置成输入模式。
当一个管脚被配置成输出模式,那么到底输出高电平还是低电平由谁决定呢,这时就 需要数据寄存器 PORTA 了,当数据方向寄存器指定了某一管脚是输出时,输出的具体电平 由 PORT*决定。
举例:我想让 PA7 管脚输出高电平,怎么写程序呢?很简单DDRA& && && && &&&|=0x80; PORTA&&|=0x80;0x 指后面数据为 16 进制,0x80=B ,|=运算就是 DDRA =DDRA | 0x80,也就是将第 7 位置 1,且不改变别的位的状态。假如你写 DDRA=0x80,那么这就意味着第 7位被置 1,其他位都被置 0。 实际应用:在我们的开发板中 led2 和 led3 分别有 PE5&&和 PE6 控制,当 PE5,PE6 为低电平时 led中有 5mA 电流流过,led 亮,当 PE5,PE6 为高电平时,led 中无电流流过,led 灭。
让 led 亮程序DDRE& && && && &&&|=0x60; /*0xC0=,即将 PE5、PE6 设置成输出模式*/PORTE &=0x9F;/*0x9F= 这时按位与操作,将 PE5、PE6 设置成低电平*/
让 led 灭程序DDRE |=0x60; /*0xC0=,即将 PE5、PE6 设置成输出模式*/ PORTE |=0x60;/*0x60= 将 PE5、PE6 设置成高电平,led 灭*/ 好啦,快去试试吧,这样就算和飞思卡尔的单片机打过招呼啦~~
12:36 上传
点击文件名下载附件
下载积分: 黑币 -5
249.77 KB, 下载次数: 0, 下载积分: 黑币 -5
Powered by【课堂】关于单片机IO口讲解
我的图书馆
【课堂】关于单片机IO口讲解
双向IO口的输出:互补推挽在51单片机的P0口工作在普通IO口模式下,为准双向IO口。而工作在第二功能状态下时,则为标准的双向IO口。由于双向IO口的输出,要求能输出高低电平,通常会采用互补推挽电路。在第二功能状态下,51单片机P0口采用的是互补推挽的输出方式。何为互补推挽呢?下面是它的等效电路图。当P0第二功能作为输出时,K1和K2两个开关轮流打开。K2闭合K1打开,就会输出高电平,并且其驱动能力很大,因为电子开关的阻值小(不像上拉电阻的值那么大)。反之K2打开,K1闭合,就会输出低电平。两个开关交替导通,互为补充,“挽”是“拉”的意思,两个电子开关分别负责在IO口输出处“推”和“拉”电流,所以称为互补推挽。这种IO口结构的优点很明显,驱动能力强,稳定可靠。缺点在于实现起来比较困难。在切换输出电平的过程中,例如从低电平切换到高电平,当K1断开时,要求尽可能快的输出高电平,也就是K2应该立即闭合;同时,如果K1还没断开,K2就提前闭合了,相同于两个开关同时导通,会直接短路,后果又会很严重。所以需要用电路控制好两个开关的协调工作。双向IO口的输入:高阻态、输入电阻双向IO口的输出,只要求能输出高低电平,因此并不是必须采用互补推挽电路。而采用互补推挽电路的好处在于,这种电路同时又可以实现高阻态的输入,从而实现标准双向IO口。当图中的K1和K2同时断开时,IO口就可以工作在高阻态的输入状态下。高阻态到底是什么样的一个概念呢?当IO口处于高阻态时,也将其称为浮空输入状态,其电平是悬浮不定的,既不是高电平也不是低电平。我们可以想象单片机在检测IO口的电平高低时,相当于在CPU里面有一个类似电压表的东西,并且这个电压表内阻很大,例如图中给出的100MΩ。在这里,我们可以把这个电压表的内阻称为P0.0口此时的输入电阻(也可以近似认为是输出阻抗,电阻是对直流电而言,而阻抗是对交流电来说的。这是模拟电路的知识,这里不做细说)。现在试想,如果不小心用手碰到了P0.0端口,而由于人体本身就是阻值很大的导体,周围有很多电磁波干扰,手上可能存在一些很微弱的电流,这个时候,电压表的读数就会发生变化,单片机读取的电平高低就会变。高阻态表现出来的结果就是外界很小的干扰,都可能导致读取的电平变化,甚至即使没有碰这个IO口,它每次读取的结果也可能不一样,因为外界的电磁波等可能会干扰到IO口。稍后我们会利用51单片机做个实验,来体验P0口的高阻态。高阻态的意义、输出电阻为什么双向IO口输入的时候要求是高阻态呢?我们假设有一种装置,等效电路如下图。开关上下切换,它就会输出高低电平,通过电压表可以检测出来。但是其驱动能力很弱,连LED也驱动不了。装置里的100kΩ,可以叫做装置的输出电阻(同样也可以近似认为是输出阻抗)。让这个装置输出低电平,然后连接51单片机的P1.0口。这时,VCC经过10kΩ上拉电阻到达IO口,再到装置内部的100kΩ电阻,通过开关K接到GND。根据分压原理,P1.0上的电压值大概是4.55V,于是单片机读取的是高电平。而事实是,装置想输出低电平告知51单片机。这里单片机管脚作为输入功能,却干扰了外界装置的输出值,相当于单片机的这个IO口也在输出。当单片机的P0口工作在第二功能的输入状态,或者工作在普通IO口的输入状态,且没有外界上下拉电阻,内部的两个电子开关都是断开的,对外部呈现高阻态。从图中可以看出,装置输出的电平能被准确的读取到单片机中。之所以能准确读取,就是因为装置输出电阻比单片机IO口的输入电阻要小。有人可能会说,如果把装置中的电阻换成1000MΩ,这个时候这个单片机又不能准确读取电平了。但是一般情况下,我们不需要考虑这么极端。如果是理想的高阻态,其输入阻抗应该是无穷大,而这有点像超导体一样比较特殊。一般情况下认为导线电阻几乎为0,同样也认为高阻态输入电阻是无穷大。总的来说,就是高阻态情况下,IO口输入电阻很大,而不容易干扰那些输出电阻较大、驱动能力弱的装置输出到IO口上的电平。
TA的最新馆藏[转]&[转]&[转]&[转]&[转]&[转]&
喜欢该文的人也喜欢

我要回帖

更多关于 单片机c语言编程300例 的文章

 

随机推荐