打印
[LOOK]

基于 LOOK 系统的助学板 DS18B20 示例

[复制链接]
14542|31
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 hotpower 于 2011-5-23 19:04 编辑

这是一个基于LOOK系统的助学板示例,展示了如何定义任务类与中断类,如何创建任务类实例及中断类实例,如何在任务例程及中断例程中访问同步对象(信号灯、邮箱)。
示例涉及到的外设有:UART0, UART1, GPIO。
运行过程:当用户按 KEY1 时,程序通过 UART1 读取 DS18B20 的温度值并转换为文本信息发送到 UART0。按 KEY2 时,将读取 DS18B20 的 ROM 信息并转换为文本发送到 UART0。
 
#include "nuc1xx.h"
#include "NUC1xxM051SeriesCfg.h"
#include <look.h>
#include <look/instantiate>
LOOK_HWINIT()
{
    // 初始化系统时钟
    UNLOCKREG(0);                           // 解锁
    SYSCLKs.PWRCON.Bits.XTL12M_EN = 1;      // 外部晶振使能
    volatile uintptr_t n = 10000;
    while (--n);                            // 延时等待晶振稳定
    SYSCLKs.PLLCON.Regs &= ~((1 << SYSCLK_PLLCON_PD)
                            | (1 << SYSCLK_PLLCON_OE));     // PLL输出使能
    n = 10000;
    while (--n);                            // 延时等待PLL稳定
    SYSCLKs.CLKSEL0.Bits.HCLK_S = 2;        // 选择CPU时钟为PLL
    SYSCLKs.CLKSEL1.Bits.UART_S = 0;        // 选择UART时钟为外部晶振
    SYSCLKs.APBCLK.Regs = (1 << SYSCLK_APBCLK_UART0_EN)     // UART0时钟使能
                        | (1 << SYSCLK_APBCLK_UART1_EN);    // UART1时钟使能
    // 防抖设置
    AHBs.AHB_GPIO.DBNCECON.Regs = (7 << GPIO_DBNCECON_DBCLKSEL)
                                | (1 << GPIO_DBNCECON_DBCLKSRC)
                                | (1 << GPIO_DBNCECON_ICLK_ON);
    // 关闭蜂鸣器
    GPIOBs.PMD.Bits.PMD10 = GPIO_PMD_OUTPUT;
    GPIOBs.DOUT.Bits.Pin10 = 0;
}
// owou_t 类为应用层提供了1-wire总线的部分操作方法(成员函数),并且封装了一些操作内部使用的数据。
class owou_t : public interrupt_t {
public:
    owou_t() __OPT_ATTR__;
    bool reset();
    int read(uintptr_t bits = 8) __OPT_ATTR__;
    int write(uintptr_t data, uintptr_t bits = 8) __OPT_ATTR__;
protected:
    bool isr(int vector);
    void dsr(int vector, uintptr_t count);
    int touch(uintptr_t data, uintptr_t bits);
private:
    sem_t sem;              // 信号灯为 1-wire 操作提供同步
    uint8_t in_data;        // 从 1-wire 总线上读出的数据。
    uint8_t out_data;       // 要写到 1-wire 总线上的数据,有效的位数由 op_count 设定。
    uint8_t op_count;       // 定义域:1 <= x <= 8:out_data 的有效数据位。
                            // 0x80:表示此次操作为 1-wire 总线复位。
};
// owou_t 构造函数
__OPT_INLINE__ owou_t:wou_t()
: sem(0)
{
    SYSs.GPBMFP.Regs |= (1 << GCR_GPBMFP_UART1_RX)
                        | (1 << GCR_GPBMFP_UART1_TX);       // 设置 UART1 引脚功能
    attach(UART1_IRQn);                                     // 挂接中断对象
    vector_t::enable(UART1_IRQn);                           // 允许 UART1_IRQn
}
// 1-wire 复位操作
bool owou_t::reset()
{
    op_count = 0x80;                                        // 设置 1-wire 总线操作为“复位”
    // 设置 UART1 参数,以产生合适的 1-wire 总线复位操作时序。
    SYSs.IPRSTC2.Bits.UART1_RST = 1;
    SYSs.IPRSTC2.Bits.UART1_RST = 0;
    UART1s.FCR.Regs |= (1 << UART_FCR_TFR) | (1 << UART_FCR_RFR);
    UART1s.LCR.Regs = 3 << UART_LCR_WLS;                    // 设置线控
    UART1s.IER.Regs = 1 << UART_IER_RDA_IEN;                // 允许接收中断
    UART1s.BAUD.Regs = (0x4e0 << UART_BAUD_BRD)
                        | (1 << UART_BAUD_DIV_X_ONE)
                        | (1 << UART_BAUD_DIV_X_EN);        // 波特率 = 9600
    UART1s.DATA.Regs = 0xf0;                                // 发出“复位”信号
    if (sem.wait(LOOK_TICKS_PER_SEC / 20)) {                // 等待“复位”应答
        if (in_data != 0xf0) {                              // “复位”应答出现
            // 收到复位应答后,重新设置 UART1 参数,用以产生合适的 1-wire 总线读写操作时序。
            SYSs.IPRSTC2.Bits.UART1_RST = 1;
            SYSs.IPRSTC2.Bits.UART1_RST = 0;
            UART1s.FCR.Regs |= (1 << UART_FCR_TFR) | (1 << UART_FCR_RFR);
            UART1s.LCR.Regs = 3 << UART_LCR_WLS;
            UART1s.IER.Regs = 1 << UART_IER_RDA_IEN;
            UART1s.BAUD.Regs = (0x66 << UART_BAUD_BRD)
                                | (1 << UART_BAUD_DIV_X_ONE)
                                | (1 << UART_BAUD_DIV_X_EN);    // 波特率 = 115200
            return true;
        }
    }
    return false;
}
// 1-wire 读操作
// 参数:
//      bits:需要读出的数据位数。定义域:1 <= x <= 8
// 返回:
//      读到的数据。
__OPT_INLINE__ int owou_t::read(uintptr_t bits)
{
    int data = touch(0xff, bits);
    if (bits < 8)
        data >>= 8 - bits;
    return data;
}
// 1-wire 写操作
// 参数:
//      data: 需要写到 1-wire 总线的数据。
//      bits:数据位数。定义域:1 <= x <= 8
__OPT_INLINE__ int owou_t::write(uintptr_t data, uintptr_t bits)
{
    return touch(data, bits);
}
// 1-wire 中断服务例程
// 当复位操作完成或读写1位完成后,中断发生。
bool owou_t::isr(int vector)
{
    uintptr_t data = UART1s.DATA.Regs;
    if ((op_count & 0x80) != 0) {       // 复位操作
        in_data = data;                 // 保存接收的数据
    } else {                            // 读写操作
        in_data = ((data << 8) + in_data) >> 1; // 组合读出的数据
        uintptr_t count = op_count;
        if (--count != 0) {
            op_count = count;
            UART1s.DATA.Regs = 0 - (out_data & 1);  // 输出 out_data 最低位(扩展为字节)。
            out_data >>= 1;
            return false;
        }                              
    }
    return true;
}
// 1-wire 中断滞后服务例程
// 当 isr() 返回 true 后(复位操作完成或所有的数据位读写操作完成),dsr() 被调用。
void owou_t::dsr(int vector, uintptr_t count)
{
    sem.do_post();          // 释放信号灯资源。
}
// 1-wire 读写例程
int owou_t::touch(uintptr_t data, uintptr_t bits)
{
    in_data = 0;
    out_data = data >> 1;
    op_count = bits;
    UART1s.DATA.Regs = 0 - (data & 1);          // 写首位
    if (sem.wait(LOOK_TICKS_PER_SEC / 20))      // 等待剩余数据位全部完成
        return in_data;
    return -1;
}
owou_t owou;                // 创建 1-wire 对象
// uart0_t 类为应用层提供了简单的 uart 同步输出功能。
class uart0_t : public interrupt_t {
public:
    uart0_t() __OPT_ATTR__;
    void puts(const char* str);
protected:
    bool isr(int vector);
    void dsr(int vector, uintptr_t count);
private:
    void fillfifo(const char* str);
private:
    const char* buffer;             // 输出缓冲区
    task_t* task;                   // 正在输出的任务
};
// uart0 构造函数
__OPT_INLINE__ uart0_t::uart0_t()
{
    SYSs.GPBMFP.Regs |= (1 << GCR_GPBMFP_UART0_RX) | (1 << GCR_GPBMFP_UART0_TX);
    attach(UART0_IRQn);
    vector_t::enable(UART0_IRQn);
    SYSs.IPRSTC2.Bits.UART0_RST = 1;
    SYSs.IPRSTC2.Bits.UART0_RST = 0;
    UART0s.FCR.Regs |= (1 << UART_FCR_TFR) | (1 << UART_FCR_RFR);
    UART0s.LCR.Regs = 3 << UART_LCR_WLS;                        // 8bits
    UART0s.BAUD.Regs = (0x66 << UART_BAUD_BRD)
                        | (1 << UART_BAUD_DIV_X_ONE)
                        | (1 << UART_BAUD_DIV_X_EN);            // 115200
}
// uart0 输出
void uart0_t::puts(const char* str)
{
    fillfifo(str);                  // 填充 fifo
    UART0s.IER.Bits.THRE_IEN = 1;   // 允许发送中断
    task = &scheduler.get_current_task();
    delay();                        // 阻塞任务
}
// uart0 中断服务例程
bool uart0_t::isr(int vector)
{
    const char* str = buffer;
    if (str == 0) {                     // 无数据
        UART0s.IER.Bits.THRE_IEN = 0;   // 禁止发送中断
        return true;
    }
    fillfifo(str);                      // 填充 fifo
    return false;
}
// uart0 中断滞后服务例程
// 所有数据发送完成后,dsr() 被调用
void uart0_t::dsr(int vector, uintptr_t count)
{
    task->do_wakeup();              // 唤醒任务
}
// uart0 填充 fifo
void uart0_t::fillfifo(const char* str)
{
    do {
        char ch;
        ch = *str++;
        if (ch == 0) {
            str = 0;
            break;
        }
        UART0s.DATA.Regs = ch;
    } while (!UART0s.FSR.Bits.TX_FULL);
    buffer = str;
}
uart0_t uart0;              // 创建 uart0 对象
mbox_t<int> mbox(0);        // 创建 int 型邮箱,初值 0
// 主任务
class task_main_t : public task_t {
public:
    task_main_t() __OPT_ATTR__;
protected:
    void routine() __attribute__((noreturn));
private:
    uint8_t buffer[12];         // 1-wire 输入数据缓冲
    char str[28];               // uart0 输出数据缓冲
};
__OPT_INLINE__ task_main_t::task_main_t()
{
}
// 主任务例程
void task_main_t::routine()
{
    while (true) {
        int msg = mbox.get();                   // 等待邮箱消息
        if (msg != 0) {
            if (owou.reset()) {
                do {
                    int n;
                    if (msg == 1) {             // 消息 1,读 ds18b20 ROM
                        owou.write(0x33);
                        n = 8;                  // 读 8 字节数据
                    } else {
                        owou.write(0xcc);
                        owou.write(0x44);
                        delay(LOOK_TICKS_PER_SEC * 0.75);
                        if (!owou.reset()) {
                            uart0.puts("reset error\n");
                            break;
                        }
                        owou.write(0xcc);
                        owou.write(0xbe);
                        n = 9;                  // 读 9 字节数据
                    }
                    // 读数据并进行 crc 校验
                    uintptr_t crc = 0;
                    int i = 0;
                    do {
                        int data = owou.read();
                        buffer = data;
                        crc ^= data;
                        for (int x = 0; x < 8; x++) {
                            uintptr_t tmp = crc;
                            crc >>= 1;
                            if (tmp & 1)
                                crc ^= 0x8c;
                        }
                    } while (++i < n);
                    if (crc == 0) {             // crc 正确
                        char* p;
                        if (msg == 1) {         // 消息 1,读 ds18b20 ROM
                            // 转换并输出 serial number 信息到 uart0
                            uart0.puts("serial number:");
                            p = str;
                            i = 0;
                            do {
                                *p++ = ' ';
                                int data = buffer;
                                int tmp = data >> 4;
                                if (tmp < 10)
                                    tmp += '0';
                                else
                                    tmp = tmp - 10 + 'A';
                                *p++ = tmp;
                                data &= 0xf;
                                if (data < 10)
                                    data += '0';
                                else
                                    data = data - 10 + 'A';
                                *p++ = data;
                            } while (++i < 8);
                            *p++ = '\n';
                            *p = 0;
                            p = str;
                        } else {                // 消息 2,读 ds18b20 scratch pad
                            // 转换并输出 temperature 信息到 uart0
                            uart0.puts("temperature:");
                            int data = *reinterpret_cast<int16_t*>(&buffer[0]);
                            bool neg = false;
                            if (data < 0) {
                                data = -data;
                                neg = true;
                            }
                            p = &str[28];
                            *--p = 0;
                            *--p = '\n';
                            uintptr_t tmp = (data & 0xf) * 625;
                            if (tmp != 0) {
                                int n = 4;
                                bool b = false;
                                do {
                                    uintptr_t rem = tmp;
                                    tmp = tmp * (((1 << 19) + 9) / 10) >> 19;
                                    rem -= tmp * 10;
                                    if (b || rem) {
                                        *--p = '0' + rem;
                                        b = true;
                                    }
                                } while (--n);
                                *--p = '.';
                            }
                            data >>= 4;
                            do {
                                uintptr_t rem = data;
                                data = data * (((1 << 11) + 9) / 10) >> 11;
                                rem -= data * 10;
                                *--p = '0' + rem;
                            } while (data);
                            if (neg)
                                *--p = '-';
                        }
                        uart0.puts(p);              // 输出信息
                    } else
                        uart0.puts("crc error\n");
                } while (false);
            } else
                uart0.puts("reset error\n");
        } else
            uart0.puts("Accident be awakened\n");
    }
}
instantiate::task<task_main_t, 30> task_main;       // 创建主任务对象
// eint_t 类提供了 INT0/INT1 的接口
// 当 INT0/INT1 发生时,对象将发送相应的 int 消息到 mbox。
class eint_t : public interrupt_t {
public:
    eint_t() __OPT_ATTR__;
protected:
    bool isr(int vector);
    void dsr(int vector, uintptr_t count);
};
// eint 构造函数
__OPT_INLINE__ eint_t::eint_t()
{
    attach(EINT0_IRQn);
    attach(EINT1_IRQn);
    GPIOBs.PMD.Bits.PMD14 = GPIO_PMD_INPUT;                 // GPIOB14 设置为输入方式
    GPIOBs.PMD.Bits.PMD15 = GPIO_PMD_INPUT;                 // GPIOB15 设置为输入方式
    SYSs.GPBMFP.Regs |= (1 << GCR_GPBMFP_INT1_SS31)         // 复用 INT1
                        | (1 << GCR_GPBMFP_INT0);           // 复用 INT0
    GPIOBs.DBEN.Regs = (1 << Pin15) | (1 << Pin14);         // 开启防抖
    GPIOBs.IEN.Regs = (1 << Pin15) | (1 << Pin14);          // 开启中断
    vector_t::enable(EINT0_IRQn);
    vector_t::enable(EINT1_IRQn);
}
// eint 中断服务例程
bool eint_t::isr(int vector)
{
    GPIOBs.ISRC.Regs = GPIOBs.ISRC.Regs;            // 清中断 flag
    return true;
}
// eint 中断滞后服务例程
void eint_t::dsr(int vector, uintptr_t count)
{
    mbox.do_tryput(vector == EINT0_IRQn ? 2 : 1);       // 发送消息
}
eint_t eint;                                    // 创建 eint 对象
namespace look {
    sched_t scheduler __attribute__((init_priority(112)));  // 创建调度器
    systick_t systick(48000000 / LOOK_TICKS_PER_SEC);       // 创建系统节拍对象
    // 定义中断向量表
    void (*const vector_t::vectors[])() = {
        stack,                  // 0
        reset,                  // 1
        nmi,                    // 2
        hard_fault,             // 3
        0,                      // 4
        0,                      // 5
        0,                      // 6
        0,                      // 7
        0,                      // 8
        0,                      // 9
        0,                      // 10
        base::sched_t::svcall,  // 11
        0,                      // 12
        0,                      // 13
        base::sched_t::pendsv,  // 14
        vsr,                    // 15, systick
        vsr,                    // IRQ0
        vsr,                    // IRQ1
        vsr,                    // IRQ2
        vsr,                    // IRQ3
        vsr,                    // IRQ4
        vsr,                    // IRQ5
        vsr,                    // IRQ6
        vsr,                    // IRQ7
        vsr,                    // IRQ8
        vsr,                    // IRQ9
        vsr,                    // IRQ10
        vsr,                    // IRQ11
        vsr,                    // IRQ12
        vsr,                    // IRQ13
        vsr,                    // IRQ14
        vsr,                    // IRQ15
        vsr,                    // IRQ16
        vsr,                    // IRQ17
        vsr,                    // IRQ18
        vsr,                    // IRQ19
        vsr,                    // IRQ20
        vsr,                    // IRQ21
        vsr,                    // IRQ22
        vsr,                    // IRQ23
        vsr,                    // IRQ24
        vsr,                    // IRQ25
        vsr,                    // IRQ26
        vsr,                    // IRQ27
        vsr,                    // IRQ28
        vsr,                    // IRQ29
        vsr,                    // IRQ30
        vsr                     // IRQ31
    };
    vector_t vector_t::table[sizeof(vectors) / sizeof(vectors[0]) - 15];
}
评分
参与人数 2威望 +11 收起 理由
hotpower + 10
dong_abc + 1

相关帖子

沙发
murex| | 2011-4-3 22:44 | 只看该作者
老师的好贴一定要顶

使用特权

评论回复
板凳
hotpower| | 2011-4-3 22:45 | 只看该作者
本帖最后由 hotpower 于 2011-5-30 13:29 编辑

给力Look!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

俺运行的图:

使用特权

评论回复
地板
Cube| | 2011-4-3 23:08 | 只看该作者
拜读中:)

使用特权

评论回复
5
xjm05413| | 2011-4-3 23:25 | 只看该作者
传说中的Look~~~~~

使用特权

评论回复
6
tear086| | 2011-4-4 00:26 | 只看该作者
看CPP,好吃力。

使用特权

评论回复
7
john_lee|  楼主 | 2011-4-4 02:09 | 只看该作者
示例中相当大的一部分都是程序框架,属于定式(可能以后会用wizard自动生成),除开这些后,程序实际上是很简单的。

为了简单起见,示例只用了一个任务,但却展示出了RTOS的大部分元素:任务,中断,同步对象。

以后我会给出更多的示例,逐步展示出LOOK更多的特点,如:多任务调度,信号系统,以及如何扩展LOOK(为LOOK提供用户自己的调度器,抽象任务类和同步对象)等等。

使用特权

评论回复
8
hotpower| | 2011-4-4 02:10 | 只看该作者
呵呵,要学习优秀的技术

使用特权

评论回复
9
john_lee|  楼主 | 2011-4-4 02:28 | 只看该作者
程序大概的运行流程:
1、运行LOOK_HWINIT()函数中的代码。
2、运行scheduler构造函数。
     sched_t scheduler __attribute__((init_priority(112)));  // 创建调度器
3、运行各个对象的构造函数(没有固定的顺序):
     systick_t systick(48000000 / LOOK_TICKS_PER_SEC);       // 创建系统节拍对象
     owou_t owou;                // 创建 1-wire 对象
     uart0_t uart0;              // 创建 uart0 对象
     mbox_t<int> mbox(0);        // 创建 int 型邮箱,初值 0
     instantiate::task<task_main_t, 30> task_main;       // 创建主任务对象
     eint_t eint;                                    // 创建 eint 对象
4、运行主任务例程:void task_main_t::routine()

使用特权

评论回复
评分
参与人数 1威望 +1 收起 理由
dong_abc + 1
10
john_lee|  楼主 | 2011-4-4 02:40 | 只看该作者
本帖最后由 john_lee 于 2011-4-4 02:53 编辑

使用-Os优化编译连接后的目标文件大小:
ROM占用:3224,其中LOOK系统占用1380
RAM占用:704,其中LOOK系统占用412

使用特权

评论回复
11
hotpower| | 2011-4-4 07:23 | 只看该作者
希望老师多出例程,早日文档与普及,辛苦了!

使用特权

评论回复
12
Swallow_0322| | 2011-4-4 08:10 | 只看该作者
传说中的LOOK,现仅止步于羡慕,希望通过老师越来越多的例程,俺也能向它迈入一小步,(*^__^*) 嘻嘻……
高端!:victory:

使用特权

评论回复
13
dong_abc| | 2011-4-4 15:13 | 只看该作者
好贴!

使用特权

评论回复
14
maxking| | 2011-4-4 19:54 | 只看该作者
能做出一个在液晶12232显示出来的就好了。

使用特权

评论回复
15
hotpower| | 2011-4-5 11:21 | 只看该作者
老师已在QQ群(12047788)里讲授LOOK的基本原理和实现。

使用特权

评论回复
16
hotpower| | 2011-4-5 11:21 | 只看该作者
老师已在QQ群(12047788)里讲授LOOK的基本原理和实现。

使用特权

评论回复
17
plc_avr| | 2011-4-8 10:47 | 只看该作者
有空时慢慢看........

使用特权

评论回复
18
hotpower| | 2011-4-14 17:52 | 只看该作者
希望有更多的例程才能有利于普及

使用特权

评论回复
19
john_lee|  楼主 | 2011-4-21 21:30 | 只看该作者
本帖最后由 john_lee 于 2011-5-16 19:27 编辑

使用 Wizard 后的 简化文件,cpp:
#include "nuc1xx.h"
#include "NUC1xxM051SeriesCfg.h"
#include "task.h"           // 此处需要更改为 Wizard 生成的 “目标文件名.h”
// owou_t 类为应用层提供了1-wire总线的部分操作方法(成员函数),并且封装了一些操作内部使用的数据。
class owou_t : public interrupt_t {
public:
    owou_t() __OPT_ATTR__;
    bool reset();
    int read(uintptr_t bits = 8) __OPT_ATTR__;
    int write(uintptr_t data, uintptr_t bits = 8) __OPT_ATTR__;
protected:
    bool isr(int vector);
    void dsr(int vector, uintptr_t count);
    int touch(uintptr_t data, uintptr_t bits);
private:
    sem_t sem;              // 信号灯为 1-wire 操作提供同步
    uint8_t in_data;        // 从 1-wire 总线上读出的数据。
    uint8_t out_data;       // 要写到 1-wire 总线上的数据,有效的位数由 op_count 设定。
    uint8_t op_count;       // 定义域:1 <= x <= 8:out_data 的有效数据位。
                            // 0x80:表示此次操作为 1-wire 总线复位。
};
// owou_t 构造函数
__OPT_INLINE__ owou_t:wou_t()
: sem(0)
{
//  SYSs.GPBMFP.Regs |= (1 << GCR_GPBMFP_UART1_RX)
//                      | (1 << GCR_GPBMFP_UART1_TX);       // 设置 UART1 引脚功能
    attach(UART1_IRQn);                                     // 挂接中断对象
    vector_t::enable(UART1_IRQn);                           // 允许 UART1_IRQn
}
// 1-wire 复位操作
bool owou_t::reset()
{
    op_count = 0x80;                                        // 设置 1-wire 总线操作为“复位”
    // 设置 UART1 参数,以产生合适的 1-wire 总线复位操作时序。
    SYSs.IPRSTC2.Bits.UART1_RST = 1;
    SYSs.IPRSTC2.Bits.UART1_RST = 0;
    UART1s.FCR.Regs |= (1 << UART_FCR_TFR) | (1 << UART_FCR_RFR);
    UART1s.LCR.Regs = 3 << UART_LCR_WLS;                    // 设置线控
    UART1s.IER.Regs = 1 << UART_IER_RDA_IEN;                // 允许接收中断
    UART1s.BAUD.Regs = (0x4e0 << UART_BAUD_BRD)
                        | (1 << UART_BAUD_DIV_X_ONE)
                        | (1 << UART_BAUD_DIV_X_EN);        // 波特率 = 9600
    UART1s.DATA.Regs = 0xf0;                                // 发出“复位”信号
    if (sem.wait(LOOK_TICKS_PER_SEC / 20)) {                // 等待“复位”应答
        if (in_data != 0xf0) {                              // “复位”应答出现
            // 收到复位应答后,重新设置 UART1 参数,用以产生合适的 1-wire 总线读写操作时序。
            SYSs.IPRSTC2.Bits.UART1_RST = 1;
            SYSs.IPRSTC2.Bits.UART1_RST = 0;
            UART1s.FCR.Regs |= (1 << UART_FCR_TFR) | (1 << UART_FCR_RFR);
            UART1s.LCR.Regs = 3 << UART_LCR_WLS;
            UART1s.IER.Regs = 1 << UART_IER_RDA_IEN;
            UART1s.BAUD.Regs = (0x66 << UART_BAUD_BRD)
                                | (1 << UART_BAUD_DIV_X_ONE)
                                | (1 << UART_BAUD_DIV_X_EN);    // 波特率 = 115200
            return true;
        }
    }
    return false;
}
// 1-wire 读操作
// 参数:
//      bits:需要读出的数据位数。定义域:1 <= x <= 8
// 返回:
//      读到的数据。
__OPT_INLINE__ int owou_t::read(uintptr_t bits)
{
    int data = touch(0xff, bits);
    if (bits < 8)
        data >>= 8 - bits;
    return data;
}
// 1-wire 写操作
// 参数:
//      data: 需要写到 1-wire 总线的数据。
//      bits:数据位数。定义域:1 <= x <= 8
__OPT_INLINE__ int owou_t::write(uintptr_t data, uintptr_t bits)
{
    return touch(data, bits);
}
// 1-wire 中断服务例程
// 当复位操作完成或读写1位完成后,中断发生。
bool owou_t::isr(int vector)
{
    uintptr_t data = UART1s.DATA.Regs;
    if ((op_count & 0x80) != 0) {       // 复位操作
        in_data = data;                 // 保存接收的数据
    } else {                            // 读写操作
        in_data = ((data << 8) + in_data) >> 1; // 组合读出的数据
        uintptr_t count = op_count;
        if (--count != 0) {
            op_count = count;
            UART1s.DATA.Regs = 0 - (out_data & 1);  // 输出 out_data 最低位(扩展为字节)。
            out_data >>= 1;
            return false;
        }                              
    }
    return true;
}
// 1-wire 中断滞后服务例程
// 当 isr() 返回 true 后(复位操作完成或所有的数据位读写操作完成),dsr() 被调用。
void owou_t::dsr(int vector, uintptr_t count)
{
    sem.do_post();          // 释放信号灯资源。
}
// 1-wire 读写例程
int owou_t::touch(uintptr_t data, uintptr_t bits)
{
    in_data = 0;
    out_data = data >> 1;
    op_count = bits;
    UART1s.DATA.Regs = 0 - (data & 1);          // 写首位
    if (sem.wait(LOOK_TICKS_PER_SEC / 20))      // 等待剩余数据位全部完成
        return in_data;
    return -1;
}
owou_t owou;                // 创建 1-wire 对象
// uart0_t 类为应用层提供了简单的 uart 同步输出功能。
class uart0_t : public interrupt_t {
public:
    uart0_t() __OPT_ATTR__;
    void puts(const char* str);
protected:
    bool isr(int vector);
    void dsr(int vector, uintptr_t count);
private:
    void fillfifo(const char* str);
private:
    const char* buffer;             // 输出缓冲区
    task_t* task;                   // 正在输出的任务
};
// uart0 构造函数
__OPT_INLINE__ uart0_t::uart0_t()
{
//  SYSs.GPBMFP.Regs |= (1 << GCR_GPBMFP_UART0_RX) | (1 << GCR_GPBMFP_UART0_TX);
    attach(UART0_IRQn);
    vector_t::enable(UART0_IRQn);
    SYSs.IPRSTC2.Bits.UART0_RST = 1;
    SYSs.IPRSTC2.Bits.UART0_RST = 0;
    UART0s.FCR.Regs |= (1 << UART_FCR_TFR) | (1 << UART_FCR_RFR);
    UART0s.LCR.Regs = 3 << UART_LCR_WLS;                        // 8bits
    UART0s.BAUD.Regs = (0x66 << UART_BAUD_BRD)
                        | (1 << UART_BAUD_DIV_X_ONE)
                        | (1 << UART_BAUD_DIV_X_EN);            // 115200
}
// uart0 输出
void uart0_t::puts(const char* str)
{
    fillfifo(str);                  // 填充 fifo
    UART0s.IER.Bits.THRE_IEN = 1;   // 允许发送中断
    task = &scheduler.get_current_task();
    delay();                        // 阻塞任务
}
// uart0 中断服务例程
bool uart0_t::isr(int vector)
{
    const char* str = buffer;
    if (str == 0) {                     // 无数据
        UART0s.IER.Bits.THRE_IEN = 0;   // 禁止发送中断
        return true;
    }
    fillfifo(str);                      // 填充 fifo
    return false;
}
// uart0 中断滞后服务例程
// 所有数据发送完成后,dsr() 被调用
void uart0_t::dsr(int vector, uintptr_t count)
{
    task->do_wakeup();              // 唤醒任务
}
// uart0 填充 fifo
void uart0_t::fillfifo(const char* str)
{
    do {
        char ch;
        ch = *str++;
        if (ch == 0) {
            str = 0;
            break;
        }
        UART0s.DATA.Regs = ch;
    } while (!UART0s.FSR.Bits.TX_FULL);
    buffer = str;
}
uart0_t uart0;              // 创建 uart0 对象
mbox_t<int> mbox(0);        // 创建 int 型邮箱,初值 0
// 主任务例程
void task_main_t::routine()
{
    while (true) {
        int msg = mbox.get();                   // 等待邮箱消息
        if (msg != 0) {
            if (owou.reset()) {
                do {
                    int n;
                    if (msg == 1) {             // 消息 1,读 ds18b20 ROM
                        owou.write(0x33);
                        n = 8;                  // 读 8 字节数据
                    } else {
                        owou.write(0xcc);
                        owou.write(0x44);
                        delay(LOOK_TICKS_PER_SEC * 0.75);
                        if (!owou.reset()) {
                            uart0.puts("reset error\n");
                            break;
                        }
                        owou.write(0xcc);
                        owou.write(0xbe);
                        n = 9;                  // 读 9 字节数据
                    }
                    // 读数据并进行 crc 校验
                    uintptr_t crc = 0;
                    int i = 0;
                    do {
                        int data = owou.read();
                        buffer = data;
                        crc ^= data;
                        for (int x = 0; x < 8; x++) {
                            uintptr_t tmp = crc;
                            crc >>= 1;
                            if (tmp & 1)
                                crc ^= 0x8c;
                        }
                    } while (++i < n);
                    if (crc == 0) {             // crc 正确
                        char* p;
                        if (msg == 1) {         // 消息 1,读 ds18b20 ROM
                            // 转换并输出 serial number 信息到 uart0
                            uart0.puts("serial number:");
                            p = str;
                            i = 0;
                            do {
                                *p++ = ' ';
                                int data = buffer;
                                int tmp = data >> 4;
                                if (tmp < 10)
                                    tmp += '0';
                                else
                                    tmp = tmp - 10 + 'A';
                                *p++ = tmp;
                                data &= 0xf;
                                if (data < 10)
                                    data += '0';
                                else
                                    data = data - 10 + 'A';
                                *p++ = data;
                            } while (++i < 8);
                            *p++ = '\n';
                            *p = 0;
                            p = str;
                        } else {                // 消息 2,读 ds18b20 scratch pad
                            // 转换并输出 temperature 信息到 uart0
                            uart0.puts("temperature:");
                            int data = *reinterpret_cast<int16_t*>(&buffer[0]);
                            bool neg = false;
                            if (data < 0) {
                                data = -data;
                                neg = true;
                            }
                            p = &str[28];
                            *--p = 0;
                            *--p = '\n';
                            uintptr_t tmp = (data & 0xf) * 625;
                            if (tmp != 0) {
                                int n = 4;
                                bool b = false;
                                do {
                                    uintptr_t rem = tmp;
                                    tmp = tmp * (((1 << 19) + 9) / 10) >> 19;
                                    rem -= tmp * 10;
                                    if (b || rem) {
                                        *--p = '0' + rem;
                                        b = true;
                                    }
                                } while (--n);
                                *--p = '.';
                            }
                            data >>= 4;
                            do {
                                uintptr_t rem = data;
                                data = data * (((1 << 11) + 9) / 10) >> 11;
                                rem -= data * 10;
                                *--p = '0' + rem;
                            } while (data);
                            if (neg)
                                *--p = '-';
                        }
                        uart0.puts(p);              // 输出信息
                    } else
                        uart0.puts("crc error\n");
                } while (false);
            } else
                uart0.puts("reset error\n");
        } else
            uart0.puts("Accident be awakened\n");
    }
}
instantiate::task<task_main_t, LOOK_STACK_SIZE> task_main;      // 创建主任务对象
// eint_t 类提供了 INT0/INT1 的接口
// 当 INT0/INT1 发生时,对象将发送相应的 int 消息到 mbox。
class eint_t : public interrupt_t {
public:
    eint_t() __OPT_ATTR__;
protected:
    bool isr(int vector);
    void dsr(int vector, uintptr_t count);
};
// eint 构造函数
__OPT_INLINE__ eint_t::eint_t()
{
    attach(EINT0_IRQn);
    attach(EINT1_IRQn);
//  GPIOBs.PMD.Bits.PMD14 = GPIO_PMD_INPUT;                 // GPIOB14 设置为输入方式
//  GPIOBs.PMD.Bits.PMD15 = GPIO_PMD_INPUT;                 // GPIOB15 设置为输入方式
//  SYSs.GPBMFP.Regs |= (1 << GCR_GPBMFP_INT1_SS31)         // 复用 INT1
//                      | (1 << GCR_GPBMFP_INT0);           // 复用 INT0
//  GPIOBs.DBEN.Regs = (1 << Pin15) | (1 << Pin14);         // 开启防抖
    GPIOBs.IEN.Regs = (1 << Pin15) | (1 << Pin14);          // 开启中断
    vector_t::enable(EINT0_IRQn);
    vector_t::enable(EINT1_IRQn);
}
// eint 中断服务例程
bool eint_t::isr(int vector)
{
    GPIOBs.ISRC.Regs = GPIOBs.ISRC.Regs;            // 清中断 flag
    return true;
}
// eint 中断滞后服务例程
void eint_t::dsr(int vector, uintptr_t count)
{
    mbox.do_tryput(vector == EINT0_IRQn ? 2 : 1);       // 发送消息
}
eint_t eint;                                    // 创建 eint 对象
目标文件名.h中,需要在
    void routine();          // 任务例程
之后,插入下面的代码:
private:
    uint8_t buffer[12];        // 1-wire 输入数据缓冲
    char str[28];                 // uart0 输出数据缓冲
init_config.h 的 Configuration Wizard配置:
时钟配置 \ 外设时钟配置 \ UART_S: 选择“外部 4~24Mhz 晶振时钟”
时钟配置 \ 外设时钟配置 \ UART0_EN: YES
时钟配置 \ 外设时钟配置 \ UART1_EN: YES
GPIOB 管脚配置 \ GPB_MFP, ALT_MFP: 多功能管脚选择 \ PB.0: 选择 “RXD0”
GPIOB 管脚配置 \ GPB_MFP, ALT_MFP: 多功能管脚选择 \ PB.1: 选择 “TXD0”
GPIOB 管脚配置 \ GPB_MFP, ALT_MFP: 多功能管脚选择 \ PB.4: 选择 “RXD1”
GPIOB 管脚配置 \ GPB_MFP, ALT_MFP: 多功能管脚选择 \ PB.5: 选择 “TXD1”
GPIOB 管脚配置 \ GPB_MFP, ALT_MFP: 多功能管脚选择 \ PB.14: 选择 “INT0”
GPIOB 管脚配置 \ GPB_MFP, ALT_MFP: 多功能管脚选择 \ PB.15: 选择 “INT1”
GPIOB 管脚配置 \ GPIOB_PMD: 端口模式 \ PB.10: 选择 “输出”
GPIOB 管脚配置 \ GPIOB_PMD: 端口模式 \ PB.14: 选择 “输入”
GPIOB 管脚配置 \ GPIOB_PMD: 端口模式 \ PB.15: 选择 “输入”
GPIOB 管脚配置 \ GPIOB_DOUT: 输出值 \ PB.10: 选择 “低”
GPIOB 管脚配置 \ GPIOB_DBEN: 去抖使能 \ PB.14: YES
GPIOB 管脚配置 \ GPIOB_DBEN: 去抖使能 \ PB.15: YES
中断去抖配置 \ DBCLKSEL 去抖采样周期选择:选择 “每 128 去抖时钟采样中断输入一次”
中断去抖配置 \ DBCLKSRC 去抖计数器时钟源选择:选择 “内部 10KHz 时钟”

应大家要求,上传工程: LOOK-DS18B20.zip (58.2 KB)

使用特权

评论回复
20
dong_abc| | 2011-4-23 13:17 | 只看该作者
程序框架做得真好~~~

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

33

主题

1466

帖子

21

粉丝