PIC的I/0端口操作

http://www.eefocus.com/xindong1492/blog/11-02/203970_ebd6f.html

对一般PIC的端口操作建议

鄙人比较熟悉PIC18,在PIC18中I/0常用有三个寄存器,稍微了解PIC的朋友,应该也很熟悉TRIS、PORT、LAT。根据一些自己实际经验以及一些指导书的提示,我们在对I/0端口操作时,最好知道一下以下几点:

1.         复位后状态:

复位以后,所有引脚被配置为输入。

2.         初始化操作:

建议在初始化端口时,首先初始化该PORT的数据锁存器(LAT或PORT寄存器),然后再初始化数据方向寄存器(TRIS)。这样将排除引脚电平出现毛刺的可能性,因为LAT 寄存器 (PORT数据锁存值)的上电状态是随机的。

3.         对于“读-修改-写操作”的理解:

任何执行写操作的指令实际都是在内部执行读-修改-写操作。若端口引脚在输入和输出状态之间切换,则执行写端口指令时必须小心。

例如,BSF PORTB, 5指令将导致PORTB 的全部 8位读入 CPU。然后该指令将 bit 5 置位并将最终数据写入 LATB。

如果 RB7

引脚为双向I/O,并且当 BSF PORTB, 5执行时定义为输入引脚,则会将引脚的输入信号本身读入 CPU

并写入LATB<7>,覆盖以前的内容。只要该RB7引脚保持输入模式,不会出现问题。然而,如果 RB7

引脚被切换为输出模式,数据锁存器中的内容就处于未知状态,导致RB7 引脚状态错误。

                对 PORTB和TRISB 执行读-修改-写操作会影响 RB7

                         ; RB<7:0> = 0001 0110

                         ;    LATB = 1001 0110

                         ;    TRISB = 1100 0000

        bsf    PORTB,5   ; read-modify-write operation.

                         ;     LATB = 0011 0110 bit 7 cleared

                         ; RB<7:0> = 1011 0110 RB7 changes to high speed

        bcf    TRISB,7   ; changes RB7 from input to output

                         ;    TRISB = 0100 0000

                             ; RB<7:0> = 0011 0110 RB7 in now driven low

一种较好的解决方案:是使用数据锁存器。指令 BSF LATB, 5将读输出锁存器中的各位,将 bit 置 1,并将结果写回到输出锁存器。这样就不会出现 LATB<7>被改变的风险了。

对 LATB和TRISB 执行读-修改-写操作不影响 RB7

                              ;         RB<7:0> = 1001 0110

                       ;     LATB = 1001 0110 bit 7 is high

                       ;    TRISB = 1100 0000

        bsf   LATB,5   ; read-modify-write operation

                       ;     LATB = 1011 0110 bit 7 has not changed

                       ; RB<7:0> = 1011 0110

        bcf   TRISB,7 ; changes RB7 from input to output

                       ;    TRISB = 0100 0000

                       ; RB<7:0> = 1011 0110 RB7 remains high

4.         PORT和 LAT寄存器之间的差异可以归纳如下:

有次偶尔在论坛上看见有人提问PORT和LAT有什么区别?现在把它归纳在此!


写 PORTx寄存器就是将数据值写入该端口锁存器。

写 LATx寄存器就是将数据值写入该端口锁存器。


读 PORTx寄存器就是读取I/O 引脚上的数据值。

读 LATx寄存器就是读取保存在该端口锁存器中的数据值。


5.         小结:

a)         输出时,赋值常用LATx寄存器;

b)         输入时,取值常用PORTx寄存器;

对PIC32MX的I/O端口操作的比较

当然前面所讲对PIC基本上中上系列的都适用;而针对PIC32MX,PIC32MX的I/0操作在以前PIC单片机的基础上又增加了很多功能,更加完整、全部,同时也方便用户使用。

除了TRIS、PORT、LAT三个基本寄存器外,还增加了SET, CLR, INV I/O 三种针对端口快速位操作PIC32MX还有ODC(Open-Drain Control register)寄存器可以实现针对每个独自的管脚是否使能漏极开路输出和CNPUE寄存器实现可单独使能/禁止输入引脚的弱上拉(当然这个可以配合监视选择性输入并在检测到引脚电平状态发生变化时产生中断使用)。的寄存器,除此之外,

对于这些寄存器说明在PIC32MX的数据手册里都可以找到,这里就不作详细说明。


我们在讲讲如何来操作这些I/0端口:

下面这次是自己在学习时一个小程序,和大家分享一下:


/*************************************************

* 项目名: i/o操作比较演示

* 效果: 开始效果----三个小灯逐一点亮;后三个小灯逐一熄灭

*        按下SW1后,变成流水灯,再按一下SW2,也变成开始的效果

* 平台: PIC32MX ETHERNET STARTER KIT

* 作者:    Andy

* 日期:   2011/1/26

*************************************************/

#include


#define SYS_FREQ (80000000ul)


// 配置位设置......

// SYSCLK = 80 MHz (8MHz Crystal/ FPLLIDIV * FPLLMUL / FPLLODIV) 系统时钟

// PBCLK = 40 MHz 外部总线时钟

// Primary Osc w/PLL (XT+,HS+,EC+PLL)总晶振

// WDT OFF      关看门狗

// Other options are don't care

#pragma config FPLLMUL = MUL_20, FPLLIDIV = DIV_2, FPLLODIV = DIV_1, FWDTEN = OFF

#pragma config POSCMOD = HS, FNOSC = PRIPLL, FPBDIV = DIV_8


//======这里有个ReadCoreTimer()或许大家都不怎么了解======

/**************************************************

* 从PIC32 Family Reference Manual, Sect. 02 CPU中可以查个PIC32MX

* 在内核中多了个Core Timer;说简单点也就是个计数器;而且这个

* 计数器是每两个系统时钟周期加1;所以也就是说:ReadCoreTimer()这

* 语句执行一次消耗两个系统时钟周期的时间。

* 我们在计算一下:(以延时1ms为例)

* SYS_FREQ = 80000000;

* tWait = 80000000/2000 * 1 = 400000;

* 也就是 ReadCoreTimer()要执行400000次;

* 消耗时间 400000*1 / 80000000 * 2(两个系统周期加1) = 1ms

**************************************************/

void DelayMs(unsigned int msec)

{

         unsigned int tWait = 0, tStart = 0;

         tWait = (SYS_FREQ/2000)*msec;

         tStart = ReadCoreTimer();

         while ((ReadCoreTimer() - tStart) < tWait);

}       



int main(void)

{

//=============位操作===========

//      _RD0 = 0;

//      _RD1 = 0;

//      _RD2 = 0;

//---- 这三种操作都是相同的结果----

//      _TRISD0 = 0;

//      _TRISD1 = 0;

//      _TRISD2 = 0;

//===========CLR寄存器操作========

//      LATDCLR = 0x0001 | 0x0002 | 0x0004;

//      TRISDCLR = 0x0001 | 0x0002 | 0x0004;

//=========Peripheral-Library操作======

         mPORTDClearBits(BIT_0 | BIT_1 | BIT_2);

         mPORTDSetPinsDigitalOut(BIT_0 | BIT_1 | BIT_2);

//=====因为PIC32MX ETHRNET Kit中SW1..SW3没有接上拉电阻====

//==========所以最好应该内部使能上拉===

         ConfigCNPullups(CN15_PULLUP_ENABLE | CN16_PULLUP_ENABLE);

//===============设置按键输入=====

         mPORTDSetPinsDigitalIn(BIT_6 | BIT_7 | BIT_13);


         while (1)

         {

                   DelayMs(200);

//               LATDINV = 0x0001;

                   mPORTDToggleBits(BIT_0);

                   DelayMs(200);

//               LATDINV = 0x0002;

                   mPORTDToggleBits(BIT_1);

                   DelayMs(200);

//               LATDINV = 0x0004;

                   mPORTDToggleBits(BIT_2);

//               if (_RD6 == 0)   //===判断SW1是否按下===

//=======这两条语句也相同的作用=========

                   if (mPORTDReadBits(BIT_6) == 0)

                   {

                            DelayMs(10);   //===消抖===

//                         if (_RD6 == 0)   //===确认====

                            if (mPORTDReadBits(BIT_6) == 0)

                            {

                                     while (1)

                                     {

                                               DelayMs(200);

//                                           LATD = 0x0004;

//========这几两条语句也相同的效果===========

                                               mPORTDWrite(0x0004);

                                               DelayMs(200);

//                                           LATD = 0x0002;

                                               mPORTDWrite(0x0002);

                                               DelayMs(200);

//                                           LATD = 0x0001;

                                               mPORTDWrite(0x0001);

//                                           if (_RD7 == 0)

                                               if (mPORTDReadBits(BIT_7) == 0)

                                               {

                                                        DelayMs(10);

//                                                     if (_RD7 == 0)

                                                        if (mPORTDReadBits(BIT_7) == 0)

                                                        {

//                                                              LATD = 0x0000;

                                                                 mPORTDClearBits(BIT_0 | BIT_1 | BIT_2);

                                                                 break;

                                                        }       

                                               }       

                                     }

                            }                

                   }       

         }



         return 0;

}       


/********************************************

* 其实从本例中可以看出:

* 简单的端口操作,其实使不使用Peripheral-Library函数

* 没有太大的差别,都是一句话的操作;

* Peripheral-Library函数更抽象点,你应该更加可以理解些

* 而自己直接对寄存器的操作,虽然看起来不怎么人性化;

* 但自己对内部寄存器有了更加深刻的理解。

* 两个方法都有自己的利弊,当然也要看个人爱好。

* 当然值得肯定是:Peripheral-Library在后续一些复杂应用

* 中有着很好的作用。-------by Andy

********************************************/



学习补充——对Core Timer的理解:

对Core Timer的理解:

PIC32 Family Reference Manual, Sect. 02 CPU上的定义:

The PIC32MX architecture includes a core

timer that is available to application programs. This timer is

implemented in the form of two co-processor registers–the Count register

(CP0_COUNT), and the Compare register (CP0_COMPARE). The Count register

is incremented every two system clock (SYSCLK) cycles. The incrementing

of Count can be optionally suspended during Debug mode. The Compare

register is used to cause a timer interrupt if desired.An interrupt is

generated when the Compare register matches the Count register. An

interrupt is taken only if it is enabled in the interrupt controller.

自己比较“锉”的翻译,呵呵,大家有能力还是自己看原文好…..呵呵….

内核定时器:

PIC32MX

构架中包涵一个直接可以被应用程序所用的“内核定时器”。这个定时器是由两个协同合作的寄存器组成而正常工作的——计数器(CP0_COUNT)和比较器(CPO_COMPARE).这个计数器每两个系统时钟周期(SYSCLK)加一,而且计数器可以选择性地被暂定在调试(Debug)模式下。比较器是用来引起计数器中断,当然前提你希望这样去做。当比较器中的值与计数器的值相同时,就会产生中断,当然前提是中断的正常工作,需要在中断控制器中使能。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,335评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,895评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,766评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,918评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,042评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,169评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,219评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,976评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,393评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,711评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,876评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,562评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,193评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,903评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,142评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,699评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,764评论 2 351

推荐阅读更多精彩内容