#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];
}