//=================================================================================================
// CPU 用 HIRC/6 = 2MHz 工作, RTC 一秒钟唤醒 CPU 一次, PA3 接 KEY 也会唤醒 CPU
// UART 2400接收10字节唤醒 CPU, 不到 10 字节, 255位无后续数据也会唤醒 CPU
// 进入主循环之前,对GP22写入7个配置字, 并写入ID, 每秒读取 ID 显示在 LCD 上
// Copyright (C) 2015 Nuvoton(SH) Technology Corp. All rights reserved
//=================================================================================================
#include "Nano1X2Series.h"
#include "IP_Init.h"
// GP22 的七个配置寄存器的值 ////////////////////////////////////////////////////////////
uint8_t const GP22_reg0[] = {0x80, 0x83, 0x0B, 0x68, 0x0E};
uint8_t const GP22_reg1[] = {0x81, 0x21, 0x44, 0xC0, 0x0d}; // 第一个字节是 opcode
uint8_t const GP22_reg2[] = {0x82, 0xA0, 0x1E, 0x00, 0x0d};
uint8_t const GP22_reg3[] = {0x83, 0xF0, 0x92, 0x07, 0x0c}; // 最后一个字节是 ID
uint8_t const GP22_reg4[] = {0x84, 0x20, 0x00, 0x20, 0x01};
uint8_t const GP22_reg5[] = {0x85, 0x50, 0x00, 0x00, 0x06};
uint8_t const GP22_reg6[] = {0x86, 0xC0, 0xC0, 0x60, 0x08};
uint8_t Str_Tx[] = {0xB7,0,0,0, 0,0,0,0} ; // 第一个字节是 opcode
uint8_t SPI_Rx[64] = " \nUART0 is OK now !" ; // 接收缓存
uint8_t COM0_Rx[64] ; // 接收缓存
uint8_t COM1_Rx[64] ; // 接收缓存
/// PA~PE都是16个GPIO, 没引出的脚也要配成输入并打开弱上拉 ///////////////////////////////
void GpioInit(void)
{
// PA 11GPIO, PA0~6,12~15
// PA0高接通V30, PA1,5_EPROM, PA2_EPROM_VCC, PA4_VCC_30, 这几个输出0
// PA12~PA14, PA15_GPIO接SPISS, PA3_KEY, PA6空
PA->DOUT = 0xFFC8 ;
PA->PMD = 0x40000595 ; // PA3 OD 输出1
PA->PUEN = 0x2FC8 ; // 1使能弱上拉
SYS->PA_H_MFP = SYS_PA_H_MFP_PA14_MFP_SPI1_SCLK
| SYS_PA_H_MFP_PA13_MFP_SPI1_MISO0
| SYS_PA_H_MFP_PA12_MFP_SPI1_MOSI0 ;
SYS->PA_L_MFP = 0 ;
// PB 11个GPIO, PB0~3,6,10~15
// PB0,1空, PB2_GP22复位输出1, PB3_INT入,PB6_Tx, PB10_Rx,PB11~12空,PB15_LCD
PB->DOUT = 0xFFFF ;
PB->PMD = 0 ;
PB->PUEN = 0x3A0F ;
PB->OFFD = 0x80000000 ; // PB15 关数字输入
SYS->PB_L_MFP = SYS_PB_L_MFP_PB6_MFP_UART1_TX ;
SYS->PB_H_MFP = SYS_PB_H_MFP_PB15_MFP_LCD_S19
| SYS_PB_H_MFP_PB14_MFP_UART0_TX
| SYS_PB_H_MFP_PB13_MFP_UART0_RX
| SYS_PB_H_MFP_PB10_MFP_UART1_RX ;
// PC无10~13, 有12个GPIO,全是LCD接口
PC->DOUT = 0xFFFF ;
PC->PMD = 0 ;
PC->PUEN = 0xFFFF ;
PC->OFFD = 0xFFFF0000;
SYS->PC_L_MFP = 0x88888888; // seg11 ~ 18
SYS->PC_H_MFP = 0x88888888; // seg7 ~ 8
// PD 有16个GPIO, PD11/12是GPIO,其它全是LCD接口
PD->DOUT = 0xE7FF ;
PD->PMD = 0 ;
PD->PUEN = 0xE7FF ;
PD->OFFD = 0xE7FF0000;
SYS->PD_L_MFP = 0x88888888; // seg6 ~ 0, COM3
SYS->PD_H_MFP = 0x88800888 | SYS_PD_H_MFP_PD12_MFP_CLK_Hz; // COM2 ~ 0, V3 ~ 1
// 64PIN 封装 PE 没引出, 也要配成输入打开弱上拉 ///////////////////////////////////////
PE->DOUT = 0xFFFF ;
PE->PMD = 0 ;
PE->PUEN = 0xFFFF ;
SYS->PE_L_MFP = 0 ;
SYS->PE_H_MFP = 0 ;
// PF012345. 有6个GPIO
PF->DOUT = 0xFFFF ;
PF->PMD = 0 ;
PF->PUEN = 0xFFFC ; // PF01/02 关弱上拉
PF->OFFD = 0x00030000 ; // PF01/02 关数字输入
SYS->PF_L_MFP = SYS_PF_L_MFP_PF1_MFP_X32_OUT
| SYS_PF_L_MFP_PF0_MFP_X32_IN ;
PA->ISRC = ~0 ; // 清标志
PA->IMD = 0 ; // 边沿中断
PA->IER = 0x00080008 ; // 上下沿中断
PA->DBEN = 0x00000008 ; // 使能去抖
GPIO->DBNCECON = 0x002F ; // HCLK 消抖 约 2.7 ms
NVIC_SetPriority(GPABC_IRQn, 2);
// NVIC->ISER[0] = 1<<GPABC_IRQn ;
}
//// SPI1 少量数据收发, 不用中断, 代码简单 //////////////////////////////////////////////
// 输入: pTr, 待发送的字符
// Num, 全双工收发送字符个数
// pRx, 接收字符存放地址
void SPI1_TxRx(uint8_t *pTx, uint32_t Num, uint8_t *pRx )
{
uint32_t Cnt = 6, CntRx = Num ;
PA->DOUT &= ~0x8000 ; // SS = 0 ;
while(Num){ --Num ;
SPI1->TX1 = *pTx++ ;
if(--Cnt == 0) break ;
}
while(CntRx){ --CntRx;
while(SPI1->STATUS & SPI_STATUS_RX_EMPTY_Msk) ;
*pRx++ = SPI1->RX1 ;
if(Num){ --Num; SPI1->TX1 = *pTx++; }
}
PA->DOUT |= 0x8000 ; // SS = 1 ;
}
/////////////////////////////////////////////////////////////////////////////////////////
int32_t main(void)
{
uint8_t *pStr ;
SysClkInit() ;
Timer1Init() ; // Delayus()延时用 Timer1
RTC_Init();
LCD_Init() ;
SPI1_Init(3) ; // SPI1 时钟是 HCLK 的3分频
PB->PMD |= 0x10 ; // PB2控制GP22复位, 低有效
// 与GPIO输出有关的外设配置放此
UART0_Init() ;
UART1_Init() ;
GpioInit() ; // 配置GPIO
UART0->THR = '\n' ; UART0->THR = 'O' ; UART0->THR = 'K' ;
UART1->THR = '\n' ; UART1->THR = 'O' ; UART1->THR = 'K' ;
//// 写 GP22 的七个配置寄存器 /////////////////////////////////////////////////////////
SPI1_TxRx((uint8_t*)GP22_reg0, 5, SPI_Rx) ;
SPI1_TxRx((uint8_t*)GP22_reg1, 5, SPI_Rx) ;
SPI1_TxRx((uint8_t*)GP22_reg2, 5, SPI_Rx) ;
SPI1_TxRx((uint8_t*)GP22_reg3, 5, SPI_Rx) ;
SPI1_TxRx((uint8_t*)GP22_reg4, 5, SPI_Rx) ;
SPI1_TxRx((uint8_t*)GP22_reg5, 5, SPI_Rx) ;
SPI1_TxRx((uint8_t*)GP22_reg6, 5, SPI_Rx) ;
Delayus(50000) ; // 等 UART 发送结束
COM0_Data.NumRx = 0 ; COM0_Data.pRx = COM0_Rx ; COM0_Data.NumRx = 60 ;
COM1_Data.NumRx = 0 ; COM1_Data.pRx = COM1_Rx ; COM1_Data.NumRx = 60 ;
Event = 0 ; pStr = 0 ;
while(1){
if((UART0->FSR & UART_FSR_RX_EMPTY_F_Msk) == 0) Event |= Event_UART0_Rx ;
if((UART1->FSR & UART_FSR_RX_EMPTY_F_Msk) == 0) Event |= Event_UART1_Rx ;
while(Event == 0){ // 无事可做, 休眠
SYS_UnlockReg() ;
CLK->PWRCTL |= CLK_PWRCTL_PWRDOWN_EN ; // 休眠功能使能位,自动清零
SCB->SCR |= 0x04 ; // 掉电模式
SYS_LockReg() ;
__wfi() ; // 进入休眠状态
}
//// 任务 1, 优先级最高, 越靠后, 优先级最低 /////////////////////////////////////////
if(Event & Event_RTC_INT){ Event &= ~Event_RTC_INT ;
SPI1_TxRx((uint8_t*)Str_Tx, 8, SPI_Rx) ; // 读出GP22的7个ID,显示在LCD上
LCD->MEM_0 = TabLCD[SPI_Rx[1]] ; LCD->MEM_0 += TabLCD[SPI_Rx[2]] << 16 ;
LCD->MEM_1 = TabLCD[SPI_Rx[3]] ; LCD->MEM_1 += TabLCD[SPI_Rx[4]] << 16 ;
LCD->MEM_2 = TabLCD[SPI_Rx[5]] ; LCD->MEM_2 += TabLCD[SPI_Rx[6]] << 16 ;
LCD->MEM_3 = TabLCD[SPI_Rx[7]] ; LCD->MEM_3 += TabLCD[8] << 16 ;
}
//// 任务 2 /////////////////////////////////////////////////////////////////////////
else if(Event & Event_KEY_PUSH){
PE->DOUT ^= 0x40 ;
Event &= ~Event_KEY_PUSH ; // 才再次处理按键
}
//// 任务 3 /////////////////////////////////////////////////////////////////////////
else if(Event & Event_UART0_Rx){
UART0->CTL |= UART_CTL_WAKE_THRESH_EN_Msk ; // 再次使能唤醒
if(pStr == 0) pStr = COM0_Rx ; // 接收数据的开头
// 处理数据 /////////////////////////////////////////////////////////////
if(pStr != COM0_Data.pRx){
if((UART0->FSR & UART_FSR_TX_FULL_F_Msk) == 0)
UART0->THR = *pStr++ ;
}
/////////////////////////////////////////////////////////////////////////
if(((TIMER1->DR - Uart0_Tick)&0xFFFFFF) > 70000){ // 70ms 无后续数据
pStr = 0 ;
COM0_Data.NumRx = 0 ; // 接收的数据丢掉
COM0_Data.pRx = COM0_Rx ;
COM0_Data.NumRx = 60 ; // 重新开始接收最多60字节
Event &= ~Event_UART0_Rx ; // 可以休眠了
}
}
//// 任务 4 /////////////////////////////////////////////////////////////////////////
else
if(Event & Event_UART1_Rx){ Event &= ~Event_UART1_Rx ;
UART1->CTL |= UART_CTL_WAKE_THRESH_EN_Msk ; // 再次使能唤醒
pStr = COM1_Rx ;
while(pStr != COM1_Data.pRx){
while(UART1->FSR & UART_FSR_TX_FULL_F_Msk) ;
UART1->THR = *pStr++ ;
Delayus(70) ;
}
while((UART1->FSR & UART_FSR_TE_F_Msk) == 0) ; // 等发送结束
COM1_Data.pRx = COM1_Rx ; COM1_Data.NumRx = 30 ; // 重新启动接收
}
/////////////////////////////////////////////////////////////////////////////////////
else Event = 0 ;
}
}