回答

收藏

【赚周年币】技术贴Week1-Day5——【 Atmel G53】PIO学习二

#线上活动 #线上活动 2262 人阅读 | 0 人回复 | 2017-01-02

本帖最后由 wambob 于 2017-1-2 18:43 编辑

       ASF库里有3个IOPORT例程,为了进一步学习IOPORT,打开了第二个例子,细看之下,发现控制管脚的函数不相同。第二个例子里直接控制端口的一个管脚。
比如:
例一中的函数
  1. ioport_set_port_dir(EXAMPLE_LED_PORT, EXAMPLE_LED_MASK, //设置LED端口、位、方向为输出
  2. IOPORT_DIR_OUTPUT);
复制代码
例二中的函数
  1. ioport_set_pin_dir(EXAMPLE_LED, IOPORT_DIR_OUTPUT);
复制代码
两个函数都可以控制端口的一个管脚,区别是,例一中的函数不仅可以控制一个管脚,还可以控制一组。PIO在数据手册中的说明是并行I/O口。相关寄存器是32位的:

实际上引出的只有一部分:

那么第三个例程给的是什么知识呢,打开例程3,发现使用的函数和例程二一样,只不过在函数参数中使用了函数返回值作为实参。
  1. ioport_set_pin_level(EXAMPLE_LED,
  2.                                 ioport_get_pin_level(EXAMPLE_BUTTON));
复制代码
我想驱动16位的LCD,结果发现一个问题。回顾例一中的控制端口的函数:
  1. /* Set LED IOPORTs high */
  2.         ioport_set_port_level(EXAMPLE_LED_PORT, EXAMPLE_LED_MASK,
  3.                         IOPORT_PIN_LEVEL_HIGH);
复制代码
这个真能控制LED脚输出高电平吗?
为什么这么说?
先看看这个函数的3个参数:
                              1.#define EXAMPLE_LED_PORT (0)          且#define IOPORT_PIOA     0            这个表示端口A,没问题
                              2.#define EXAMPLE_LED_MASK ((1 << 16))
这句表示PA端口的第17个管脚,PA16 也没问题。
                            3.这个参数是个枚举常量
  1. enum ioport_value {
  2.         IOPORT_PIN_LEVEL_LOW,  /*!< IOPORT pin value low */
  3.         IOPORT_PIN_LEVEL_HIGH, /*!< IOPORT pin value high */
  4. };
复制代码
看上去似乎没有问题。先不讲真确答案。先验证下:去掉原先的端口翻转函数
  1. ioport_toggle_port_level(EXAMPLE_LED_PORT, EXAMPLE_LED_MASK);       //翻转LED端口
复制代码
while循环里换成如下语句测试
  1. ioport_set_port_level(EXAMPLE_LED_PORT, EXAMPLE_LED_MASK,          //设置LED端口、位、电平高
  2.                         IOPORT_PIN_LEVEL_LOW);
  3. delay_ms(500);
  4. ioport_set_port_level(EXAMPLE_LED_PORT, EXAMPLE_LED_MASK,          //设置LED端口、位、电平高
  5.                         IOPORT_PIN_LEVEL_HIGH);
  6. delay_ms(500);
复制代码
目的是使端口A的PA16 输出占空比50%,周期1s的方波驱动LED闪烁,结果编译后下载到板上,LED只亮,并不闪烁。这就有问题了?
       来追根逐源下此函数原型:
  1. static inline void ioport_set_port_level(ioport_port_t port,
  2.                 ioport_port_mask_t mask, ioport_port_mask_t level)
  3. {
  4.         arch_ioport_set_port_level(port, mask, level);
  5. }
复制代码
调用了一个封装的函数,继续:
  1. __always_inline static void arch_ioport_set_port_level(ioport_port_t port,
  2.                 ioport_port_mask_t mask, ioport_port_mask_t level)
  3. {
  4.         Pio *base = arch_ioport_port_to_base(port);

  5.         base->PIO_SODR = mask & level;
  6.         base->PIO_CODR = mask & ~level;
  7. }
复制代码
端口解析后赋给了一个Pio类型的指针。
下面这两条语句当level的值为1时无论如何也不能把第一位除外的mask位置1,当level值为0时也不能把第一位除外的mask位置0;
而主程序中传过的参数是枚举常量0和1。
这个函数如果要正常工作,置1时两个参数mask和level相同。清0时相反。
修改主程序whilex循环验证代码:
  1. /* Toggle LED IOPORTs with half a second interval */
  2.                 ioport_set_port_level(EXAMPLE_LED_PORT, EXAMPLE_LED_MASK,
  3.                 EXAMPLE_LED_MASK);
  4.                 delay_ms(500);
  5.                 ioport_set_port_level(EXAMPLE_LED_PORT, EXAMPLE_LED_MASK,
  6.                 ~EXAMPLE_LED_MASK);
  7.                 delay_ms(500);
复制代码
编译后下载代码,观察板子,LED闪烁了。
                             

评分

参与人数 2 +25 收起 理由
EEboard爱板网 + 15 3周发帖养成记 奖励
loveeeboard + 10

查看全部评分

分享到:
回复

使用道具 举报

您需要登录后才可以回帖 注册/登录

本版积分规则

关闭

站长推荐上一条 /3 下一条