K60学习笔记一:PORT端口

预备C语言知识:
一.
1.

#ifndef //#idndef用来判断后面的标识符是否为未定义的。
#elseif 
#endif

在嵌入式的系统开发中,某个文件包含几个头文件,而且每个头文件都有可能都定义了同样的宏,使用#ifndef可以有效地防止对该宏的重复定义。此时第一个头文件中定义的宏变为有效定义,其他的头文件中的定义则被忽略。
2.#ifndef指令通常用于防止多次包含同意文件,也就是说,头文件可以采用类似于以下几行的设置:

#ifndef THINGS_H_
#define THINGS_H_

#endif

假设多次定义了同一头文件,当于处理器第一次遇到该包含文件时,THINGS_H_是未定义的,因此程序接着定义THINGS_H_,并处理文件的其余部分,预处理器下一次遇到该文件时,THINGS_H_早已经被定义了,因此预处理器会跳过该文件的其余部分。

3.
这里有一个问题:为什么会包含同一头文件?为什么会用头文件的名字作为#define的定义?
答:许多文件自身包含了其他文件。头文件的有些语句在一个文件中只能出现一次,标准头文件使用#ifndef来避免多次包含。
编译器提供商采用下述方法来解决这个问题,用文件名标识符,并使用大写字母,用下划线来代替字符。
eg;

#ifndef _STDIO_H_
#define _STDIO_H_
#endif

4.
枚举:枚举用来声明代表整数常量的符号名称。
可以通过enum来创建一个新的类型,并指定值。
枚举类型的目的是为了提高程序的可读性(其实也可以用#define来进行声明,但是可读性不高)
枚举型类型可以默认值也可以指定值。
5.
typeof简介:它是一种高级数据格式

typeof unsigned char BYTE
//和
#define BYTE unsigned char
//具有一样的功能
//但是typeof的功能比#define更加的强大:
//eg
typeof char * STRING
STRING NAME,NUM;
//char * NAME,char * NUM;
//和
#define STRING char * 
STRING NAME,NUM;
//char * NAME,NUM;

//对结构体也可使用typeof

6.#include “” and #include <>

#include ""//引用的头文件为程序目录的相对路径的头文件,表示在包含文件目录中去查找(包含目录是由用户在设置环境时设置的),而不在源文件目录去查找
#include <>//引用的是编译器中类库里面的头文件,使用双引号则表示首先在当前的源文件目录中查找,若未找到才到包含目录中去查找

7.

2.对于基于IAR IDE的K60芯片的野火的函数库的PORT端口来说:
有两个文件为:PORT.h和PROT.c
二:下面详细的分析这两个文件:
1.
在PORT端口的定义中,对端口的定义用的枚举类型:

//枚举端口管教
typeof enum
{
/* PTA端口 */ //0~31
    PTA0,  PTA1,  PTA2,  PTA3,  PTA4,  PTA5,  PTA6,  PTA7,  PTA8,  PTA9,  PTA10, PTA11, PTA12, PTA13, PTA14, PTA15,
    PTA16, PTA17, PTA18, PTA19, PTA20, PTA21, PTA22, PTA23, PTA24, PTA25, PTA26, PTA27, PTA28, PTA29, PTA30, PTA31,

    /* PTB端口 */ //32~63
    PTB0,  PTB1,  PTB2,  PTB3,  PTB4,  PTB5,  PTB6,  PTB7,  PTB8,  PTB9,  PTB10, PTB11, PTB12, PTB13, PTB14, PTB15,
    PTB16, PTB17, PTB18, PTB19, PTB20, PTB21, PTB22, PTB23, PTB24, PTB25, PTB26, PTB27, PTB28, PTB29, PTB30, PTB31,

    /* PTC端口 */
    PTC0,  PTC1,  PTC2,  PTC3,  PTC4,  PTC5,  PTC6,  PTC7,  PTC8,  PTC9,  PTC10, PTC11, PTC12, PTC13, PTC14, PTC15,
    PTC16, PTC17, PTC18, PTC19, PTC20, PTC21, PTC22, PTC23, PTC24, PTC25, PTC26, PTC27, PTC28, PTC29, PTC30, PTC31,

    /* PTD端口 */
    PTD0,  PTD1,  PTD2,  PTD3,  PTD4,  PTD5,  PTD6,  PTD7,  PTD8,  PTD9,  PTD10, PTD11, PTD12, PTD13, PTD14, PTD15,
    PTD16, PTD17, PTD18, PTD19, PTD20, PTD21, PTD22, PTD23, PTD24, PTD25, PTD26, PTD27, PTD28, PTD29, PTD30, PTD31,

    /* PTE端口 */
    PTE0,  PTE1,  PTE2,  PTE3,  PTE4,  PTE5,  PTE6,  PTE7,  PTE8,  PTE9,  PTE10, PTE11, PTE12, PTE13, PTE14, PTE15,
    PTE16, PTE17, PTE18, PTE19, PTE20, PTE21, PTE22, PTE23, PTE24, PTE25, PTE26, PTE27, PTE28, PTE29, PTE30, PTE31,

}PTXn_e;

//类似于查表来确定端口数值

//枚举端口
typedef enum
{
    PTA, PTB, PTC, PTD, PTE,
    PTX_MAX,
} PTX_e;
//是为了很好的表示各个端口的基地址
/*! 枚举编号 */
typedef enum
{
    PT0 , PT1 , PT2 , PT3 , PT4 , PT5 , PT6 , PT7 ,
    PT8 , PT9 , PT10, PT11, PT12, PT13, PT14, PT15,
    PT16, PT17, PT18, PT19, PT20, PT21, PT22, PT23,
    PT24, PT25, PT26, PT27, PT28, PT29, PT30, PT31,
} PTn_e;

/*! 枚举PORT 配置 */
typedef enum
{
    //中断方式和DMA请求方式,两者只能选其中一种(可以不选)
    //中断方式选择
    IRQ_ZERO     = 0x08 << PORT_PCR_IRQC_SHIFT,   //低电平触发
    IRQ_RISING   = 0x09 << PORT_PCR_IRQC_SHIFT,   //上升沿触发
    IRQ_FALLING  = 0x0A << PORT_PCR_IRQC_SHIFT,   //下降沿触发
    IRQ_EITHER   = 0x0B << PORT_PCR_IRQC_SHIFT,   //跳变沿触发
    IRQ_ONE      = 0x0C << PORT_PCR_IRQC_SHIFT,   //高电平触发

    //DMA请求选择
    DMA_RISING   = 0x01 << PORT_PCR_IRQC_SHIFT,   //上升沿触发
    DMA_FALLING  = 0x02 << PORT_PCR_IRQC_SHIFT,   //下降沿触发
    DMA_EITHER   = 0x03 << PORT_PCR_IRQC_SHIFT,   //跳变沿触发


    HDS          = 0x01 << PORT_PCR_DSE_SHIFT,    //输出高驱动能力
    PF           = 0x01 << PORT_PCR_PFE_SHIFT,    //带无源滤波器
    SSR          = 0x01 << PORT_PCR_SRE_SHIFT,    //输出慢变化率 Slow slew rate

    //下拉上拉选择
    PULLDOWN     = 0x02 << PORT_PCR_PS_SHIFT,     //下拉
    PULLUP       = 0x03 << PORT_PCR_PS_SHIFT,     //上拉

    //功能复用选择(如果不需要改变功能复用选择,保留原先的功能复用,直接选择ALT0 )
    //需要查 K60 Signal Multiplexing and Pin Assignments
    ALT0         = 0x00 << PORT_PCR_MUX_SHIFT,
    ALT1         = 0x01 << PORT_PCR_MUX_SHIFT,    //GPIO 8
    ALT2         = 0x02 << PORT_PCR_MUX_SHIFT,
    ALT3         = 0x03 << PORT_PCR_MUX_SHIFT,
    ALT4         = 0x04 << PORT_PCR_MUX_SHIFT,
    ALT5         = 0x05 << PORT_PCR_MUX_SHIFT,
    ALT6         = 0x06 << PORT_PCR_MUX_SHIFT,
    ALT7         = 0x07 << PORT_PCR_MUX_SHIFT,
} port_cfg;
//枚举PORT复用配置,采用枚举赋值,增加易读性
//其实也可以直接赋值

//一开始并不明白为什么要枚举端口号和枚举编号,枚举了管脚就可以了,头文件看到这,在看一下.C文件
PORT.C

#include "common.h" //山外K60 平台常用类型声明和宏定义

PORT端口中一共有三个函数分别为:

端口初始化和复用函数(配置MUX复用功能):
extern void port_init(PTXn_e(端口号),uint32 cfg);
端口初始化和复用函数(不改变MUX复用功能):
extern void port_init_NoALT(PTXn_e(端口号),uint32 cfg);
外部中断的服务函数:
extern void port_handler(void);

在看PORT.C

#include "commom.h" //类型声明和宏定义
#include "port.h" //自己写的函数

PORT_MemMapPtr PORTX[PTX_MAX] = {PORTA_BASE_PTR, PORTB_BASE_PTR, PORTC_BASE_PTR, PORTD_BASE_PTR, PORTE_BASE_PTR};
//PORT_MemMapPtr为一个结构体指针 ,PORTX[PTX_MAX]这个数组里面存的是各个端口的基地址
//现在懂得在PORT.H中关于枚举端口的意思。
void port_init(PTXn_e ,uint32 cfg)
{
    SIM_SCGC5 |= (SIM_SCGC5_PORTA_MASK << PTX(ptxn));                                                //开启PORTx端口 1.使能PORT时钟
//段地址属于基地址的一种
//4004_8038
//0100 0000 0000 0100 1000 0000 0011 1000
//#define PTX(PTxn(枚举管脚)) ((PTxn)>>5)
//右移5位,/2^5(32)
// SIM_SCGC5_PORTA_MASK = 0x200 0010 0000 0000 默认的开启了PORTA的时钟因为是/32?为什么是32,因为是2的次方数
//因此PTX(ptxn)的为0 1 2 3 4
//因此输入管脚口,就可以进行相应口的使能时钟

  PORT_ISFR_REG(PORTX_BASE(ptxn)) = (1<<PTn(ptxn));                           
  // 清空标志位 
//每个管脚都有相应的中断标志位
//现在理解枚举端口的含义
//#define PTn(ptxn) ((PTxn)&0x1f) 为的是中断端口的相应管脚,每个端口一共31个口,相应的管脚为1
//PORT_ISFR_REG(PORTX_BASE(ptxn))为指向端口的地址
//这一步操作的是中断状态寄存器

  PORT_PCR_REG(PORTX_BASE(PTxn), PTn(PTxn)) = cfg;
//复用引脚功能
//这句话可以复用的功能有:中断触发方式,无源滤波器,复用功能口,上下拉电阻
//操作的寄存器:引脚控制寄存器 n (PORTx_PCRn),每个管脚都有引脚控制寄存器
//PORT_PCR_REG(PORTX_BASE(PTxn), PTn(PTxn))把管脚定义到具体的一个管脚
//cfg根据数据手册进行搭配

//由此K60芯片的管脚以初始化完毕

void  port_init_NoALT(PTXn_e ptxn, uint32 cfg)
{                 
    SIM_SCGC5 |= (SIM_SCGC5_PORTA_MASK << PTX(ptxn));                                                   //开启PORTx端口

    PORT_ISFR_REG(PORTX_BASE(ptxn)) = (1<<PTn(ptxn));                                               // 清空标志位
//清空cfg里的MUX,加载寄存器里的MUX
    cfg &= ~PORT_PCR_MUX_MASK;                                                                       //清了MUX 字段(即不需要配置ALT,保持原来的ALT)
    cfg |=  (PORT_PCR_REG(PORTX_BASE(ptxn), PTn(ptxn)) & PORT_PCR_MUX_MASK);                         //读取寄存器里配置的 MUX

    PORT_PCR_REG(PORTX_BASE(ptxn), PTn(ptxn)) = cfg;                                                 // 复用功能 , 确定触发模式 ,开启上拉或下拉电阻
}

} 

//端口的外部中断功能:
首先要进行把 porta_handler 函数添加到中断向量表,不需要我们手动调用
操作:
set_vector_handler(PORTA_VECTORn , 中断函数名);
在进行这个函数解析的时候有一个很大的问题。
关于断言的使用:(一定要学好宏定义)
再开一篇····

你可能感兴趣的:(嵌入式)