英文手册: DS_N76E003_EN_Rev0_04.pdf
中文手册: DS_N76E003_SC_Rev0_04.pdf
英文手册: DS_N76E003_EN_Rev1.06.pdf
中文手册: DS_N76E003_SC_Rev1.06.pdf
keil c51: c51v957.exe
破解补丁: KEIL_Lic.rar
开发板资料下载 QQ群附件: 623495321
开发板资料下载 链接: http://pan.baidu.com/s/1cCeT7g 密码:1n7f
开发板原理图: n76e003_sch.pdf
NU Link仿真器:
https://item.taobao.com/item.htm?id=562773467355
N76E003AT20开发板:
https://item.taobao.com/item.htm?id=562773539677
官方网站bsp下载: N76E003_BSP_Keil_C51_V1.0.5.zip
官方网站bsp下载: N76E003_BSP_Keil_C51_V1.0.6.zip
2019-01-05 添加:
http://www.nuvoton.com/resource-files/Nu-Link_Keil_Driver_V2.05.6815.zip
http://www.nuvoton.com/resource-files/NuMicro_ICP_Programming_Tool_V2.05.6815.zip
本地下载: Nu-Link_Keil_Driver_V2.05.6815.zip
本地下载: NuMicro_ICP_Programming_Tool_V2.05.6815.zip
N76E003_BSP_Keil_C51_V1.0.6.zip
en-us--Nu-Link_Keil_Driver_V3.11.7470r.zip
在线
/*---------------------------------------------------------------------------------------------------------*/
/* */
/* Copyright(c) 2016 Nuvoton Technology Corp. All rights reserved. */
/* */
/*---------------------------------------------------------------------------------------------------------*/
//***********************************************************************************************************
// Nuvoton Technoledge Corp.
// Website: http://www.nuvoton.com
// E-Mail : MicroC-8bit@nuvoton.com
// Date : Apr/21/2016
//***********************************************************************************************************
//***********************************************************************************************************
// File Function: N76E003 System clock select demo code
//***********************************************************************************************************
#include <stdio.h>
#include "N76E003.h"
#include "Common.h"
#include "Delay.h"
#include "SFR_Macro.h"
#include "Function_define.h"
//========================================================================
// The test process:
// 1. Power on is run as default HIRC, show LED Fsys tickle faster
// 2. toggle P3.0 to GND.
// 2. call modify Fsys code to LIRC.
// 3. LED tickle speed slowly than before.
//========================================================================
void main(void)
{
/* Note
MCU power on system clock is HIRC (16 MHz)
Please keep P3.0 HIGH before you want to modify Fsys to LIRC
*/
Set_All_GPIO_Quasi_Mode; // In Common.h define
set_CLOEN; // Also can check P1.1 CLO pin for clock to find the Fsys change.
set_P30;
while (P30) // when P3.0 keep high, clock out HIRC
{
clr_GPIO1; // Check LED output tickle time
Timer0_Delay1ms(200);
set_GPIO1;
Timer0_Delay1ms(200);
}
////------------------------------------------------------------------------------------------------------
///*********************************** Change system closk source ***************************************/
////------------------------------------------------------------------------------------------------------
////***** HIRC enable part *****
// set_HIRCEN; //step1: enable HIRC clock source run
// while((CKSWT&SET_BIT5)==0); //step2: check ready
// clr_OSC1; //step3: switching system clock source if needed
// clr_OSC0;
// while((CKEN&SET_BIT0)==1); //step4: check system clock switching OK or NG
//
////***** LIRC enable part*****
////** Since LIRC is always enable, switch to LIRC directly
set_OSC1; //step3: switching system clock source if needed
clr_OSC0;
while((CKEN&SET_BIT0)==1); //step4: check system clock switching OK or NG
clr_HIRCEN;
////--------------------------------------------------------------------------------------------------------
/*
Now Fsys = LIRC , LED tickle slowly.
*/
while(1)
{
clr_GPIO1; // Check LED output tickle time
Timer0_Delay1ms(20);
set_GPIO1;
Timer0_Delay1ms(20);
}
/* =================== */
}
时钟源:
– 16 MHz高速内部振荡器,电源5.0V条件下±1%精度等级。全工作条件范围±2%精度等级.
– 10 kHz低速内部振荡器.
– 支持外部时钟输入.
– 支持系统时钟即时软件切换(On-the-fly)功能.
– 支持软件配置时钟除频最高至1/512.
在线
在线
void main (void)
{
InitialUART0_Timer3(9600); //UART0 Baudrate from Timer3
while(1)
{
Send_Data_To_UART0(0x33);
}
}
上面的例程是 新唐提供 UART0 输出(P06, P07), 一切正常。
但是改成 UART1 之后就不行了。
void main (void)
{
InitialUART1_Timer3(9600); //UART0 Baudrate from Timer3
while(1)
{
Send_Data_To_UART1(0x33);
}
}
在线
/*---------------------------------------------------------------------------------------------------------*/
/* */
/* Copyright(c) 2016 Nuvoton Technology Corp. All rights reserved. */
/* */
/*---------------------------------------------------------------------------------------------------------*/
//***********************************************************************************************************
// Nuvoton Technoledge Corp.
// Website: http://www.nuvoton.com
// E-Mail : MicroC-8bit@nuvoton.com
// Date : Apr/21/2016
//***********************************************************************************************************
//***********************************************************************************************************
// File Function: N76E885 ADC demo code
//***********************************************************************************************************
#include "N76E003.h"
#include "SFR_Macro.h"
#include "Function_define.h"
#include "Common.h"
#include "Delay.h"
//***************** The Following is in define in Fucntion_define.h ***************************
//****** Always include Function_define.h call the define you want, detail see main(void) *******
//***********************************************************************************************
#if 0
//#define Enable_ADC_BandGap ADCCON0|=SET_BIT3;ADCCON0&=0xF8; //Band-gap 1.22V
#endif
double Bandgap_Voltage,VDD_Voltage; //please always use "double" mode for this
unsigned char xdata ADCdataH[5], ADCdataL[5];
int ADCsumH=0, ADCsumL=0;
unsigned char ADCavgH,ADCavgL;
void READ_BANDGAP()
{
UINT8 BandgapHigh,BandgapLow,BandgapMark;
double Bandgap_Value,Bandgap_Voltage_Temp;
set_IAPEN;
IAPCN = READ_UID;
IAPAL = 0x0d;
IAPAH = 0x00;
set_IAPGO;
BandgapLow = IAPFD;
BandgapMark = BandgapLow&0xF0;
if (BandgapMark==0x80)
{
BandgapLow = BandgapLow&0x0F;
IAPAL = 0x0C;
IAPAH = 0x00;
set_IAPGO;
BandgapHigh = IAPFD;
Bandgap_Value = (BandgapHigh<<4)+BandgapLow;
Bandgap_Voltage_Temp = Bandgap_Value*3/4;
Bandgap_Voltage = Bandgap_Voltage_Temp - 33; //the actually banggap voltage value is similar this value.
}
if (BandgapMark==0x00)
{
BandgapLow = BandgapLow&0x0F;
IAPAL = 0x0C;
IAPAH = 0x00;
set_IAPGO;
BandgapHigh = IAPFD;
Bandgap_Value = (BandgapHigh<<4)+BandgapLow;
Bandgap_Voltage= Bandgap_Value*3/4;
}
if (BandgapMark==0x90)
{
IAPAL = 0x0E;
IAPAH = 0x00;
set_IAPGO;
BandgapHigh = IAPFD;
IAPAL = 0x0F;
IAPAH = 0x00;
set_IAPGO;
BandgapLow = IAPFD;
BandgapLow = BandgapLow&0x0F;
Bandgap_Value = (BandgapHigh<<4)+BandgapLow;
Bandgap_Voltage= Bandgap_Value*3/4;
}
clr_IAPEN;
// printf ("\n BG High = %bX",BandgapHigh);
// printf ("\n BG Low = %bX",BandgapLow);
// printf ("\n BG ROMMAP = %e",Bandgap_Voltage);
}
/******************************************************************************
The main C function. Program execution starts
here after stack initialization.
******************************************************************************/
void main (void)
{
double bgvalue;
unsigned int i;
InitialUART0_Timer1(115200);
READ_BANDGAP();
Enable_ADC_BandGap;
CKDIV = 0x02; // IMPORTANT!! Modify system clock to 4MHz ,then add the ADC sampling clock base to add the sampling timing.
for(i=0;i<5;i++) // All following ADC detect timing is 200uS run under 4MHz.
{
clr_ADCF;
set_ADCS;
while(ADCF == 0);
ADCdataH[i] = ADCRH;
ADCdataL[i] = ADCRL;
}
CKDIV = 0x00; // After ADC sampling, modify system clock back to 16MHz to run next code.
for(i=2;i<5;i++) // use the last 3 times data to make average
{
ADCsumH = ADCsumH + ADCdataH[i];
ADCsumL = ADCsumL + ADCdataL[i];
}
ADCavgH = ADCsumH/3;
ADCavgL = ADCsumL/3;
bgvalue = (ADCavgH<<4) + ADCavgL;
VDD_Voltage = (0x1000/bgvalue)*Bandgap_Voltage;
printf (" BG ROMMAP = %f,",Bandgap_Voltage);
printf (" VDD voltage = %f\n", VDD_Voltage);
while(1);
}
上面这个是工程 N76E003_BSP_Keil_C51_V1.0.5\Sample_Code\ADC_Bandgap\ADC_Bandgap.uvproj 的代码,
用于测量单片机的工作电压,
运行结果
结果显示单片机工作电压 3112mV
BG ROMMAP = 1210.500000, VDD voltage = 3112.497000
换一个电源,测算出来 4722 mV
BG ROMMAP = 1210.500000, VDD voltage = 4722.103000
说明:
N76E003 ADC的第8通道是用来测试内部的带隙电压的,
由于内部带隙电压很稳定,
不会随芯片的工作电压的改变而变化,
所以可以通过测量带隙电压,
然后通过ADC的值便可反推出VCC的电压,
从而用户可以实现自己的低压检测功能。Bandgap voltage reference,常常有人简单地称它为Bandgap。
是利用一个与温度成正比的电压与二极管压降之和,二者温度系数相互抵消,
实现与温度无关的电压基准。因为其基准电压与硅的带隙电压差不多,
因而称为带隙基准。实际上利用的不是带隙电压。
现在有些Bandgap结构输出电压与带隙电压也不一致。
在线
/*---------------------------------------------------------------------------------------------------------*/
/* */
/* Copyright(c) 2017 Nuvoton Technology Corp. All rights reserved. */
/* */
/*---------------------------------------------------------------------------------------------------------*/
//***********************************************************************************************************
// Nuvoton Technoledge Corp.
// Website: http://www.nuvoton.com
// E-Mail : MicroC-8bit@nuvoton.com
// Date : Apr/21/2017
//***********************************************************************************************************
//***********************************************************************************************************
// File Function: N76E003 wake up timer interrupt demo code
//***********************************************************************************************************
#include "N76E003.h"
#include "Common.h"
#include "Delay.h"
#include "SFR_Macro.h"
#include "Function_define.h"
void WakeUp_Timer_ISR (void) interrupt 17 //ISR for self wake-up timer
{
clr_GPIO1;
Timer1_Delay10ms(5);
set_GPIO1;
Timer1_Delay10ms(5);
clr_GPIO1;
Timer1_Delay10ms(5);
set_GPIO1;
clr_WKTF; //clear interrupt flag
}
/************************************************************************************************************
* Main function
************************************************************************************************************/
void main (void)
{
P15_PushPull_Mode;
clr_GPIO1;
Timer0_Delay1ms(400);
set_GPIO1;
Timer0_Delay1ms(400);
clr_GPIO1;
Timer0_Delay1ms(400);
set_GPIO1;
Timer0_Delay1ms(400);
clr_GPIO1;
Timer0_Delay1ms(400);
set_GPIO1;
//-----------------------------------------------------
// WKT initial
//-----------------------------------------------------
WKCON = 0x07; //timer base 10k, Pre-scale = 1/16
// RWK = 0XFF; // if prescale is 0x00, never set RWK = 0xff
RWK = 0xF0;
set_EWKT; // enable WKT interrupt
set_WKTR; // Wake-up timer run
EA = 1;
while(1)
{
set_PD; //进入掉电模式
}
}
从这个工程修改: N76E003_BSP_Keil_C51_V1.0.5\Sample_Code\WakeupTimer_INT\WKT_INT.uvproj
N76E003 掉电模式与唤醒.
在线
/*---------------------------------------------------------------------------------------------------------*/
/* */
/* Copyright(c) 2017 Nuvoton Technology Corp. All rights reserved. */
/* */
/*---------------------------------------------------------------------------------------------------------*/
//***********************************************************************************************************
// Nuvoton Technoledge Corp.
// Website: http://www.nuvoton.com
// E-Mail : MicroC-8bit@nuvoton.com
// Date : Apr/21/2017
//***********************************************************************************************************
//***********************************************************************************************************
// File Function: N76E003 Read actual bandgap value by IAP command
//***********************************************************************************************************
#include "N76E003.h"
#include "Common.h"
#include "Delay.h"
#include "SFR_Macro.h"
#include "Function_define.h"
UINT8 UID_BYTE(UINT8 Addr)
{
UINT8 DATATEMP;
set_IAPEN;
IAPAL = Addr;
IAPAH = 0x00;
IAPCN = READ_UID;
set_IAPGO;
DATATEMP = IAPFD;
clr_IAPEN;
return DATATEMP;
}
void main(void)
{
UINT8 i = 0;
UINT8 READ[12];
Set_All_GPIO_Quasi_Mode;
InitialUART0_Timer3(115200);
//---------toggle GPIO1---------
clr_GPIO1;
Timer0_Delay1ms(100);
set_GPIO1;
Timer0_Delay1ms(100);
clr_GPIO1;
Timer0_Delay1ms(100);
set_GPIO1;
Timer0_Delay1ms(100);
//---------end toggle GPIO1---------
for(i=0;i<12;i++)
READ[i] = UID_BYTE(i);
while(1)
{
printf("UID: ");
for(i=0;i<12;i++)
{
printf("%bx", READ[i]);
}
printf ("\n");
}
}
工程: N76E003_BSP_Keil_C51_V1.0.5\Sample_Code\IAP_Read_UID\UID.uvproj
读 N76E003 96bit UID
输出结果:
UID: 223100455f3637afb00
UID: 223100455f3637afb00
UID: 223100455f3637afb00
UID: 223100455f3637afb00
UID: 223100455f3637afb00
在线
在线
/*---------------------------------------------------------------------------------------------------------*/
/* */
/* Copyright(c) 2017 Nuvoton Technology Corp. All rights reserved. */
/* */
/*---------------------------------------------------------------------------------------------------------*/
//***********************************************************************************************************
// Nuvoton Technoledge Corp.
// Website: http://www.nuvoton.com
// E-Mail : MicroC-8bit@nuvoton.com
// Date : Apr/21/2017
//***********************************************************************************************************
//***********************************************************************************************************
// File Function: N76E003 APROM program DATAFLASH (APROM) demo code
//***********************************************************************************************************
#include "N76E003.h"
#include "Common.h"
#include "Delay.h"
#include "SFR_Macro.h"
#include "Function_define.h"
#define CID_READ 0x0B
#define DID_READ 0x0C
/*
Since the DATAFLASH is in the APROM. Program command is same as program APROM
*/
#define PAGE_ERASE_LD 0x62
#define BYTE_READ_LD 0x40
#define BYTE_PROGRAM_LD 0x61
#define PAGE_SIZE 128
#define ERASE_FAIL 0x70
#define PROGRAM_FAIL 0x71
#define IAPFF_FAIL 0x72
#define IAP_PASS 0x00
//---------------------------------------------------------------
// Following define by customer
// Please confirm the start addresss not over your code size
//---------------------------------------------------------------
#define DATA_SIZE 1024*4
#define DATA_START_ADDR 0x0000
/********************************************************************************************
Following IAP command register is also define in SFR_Macro.h
#define set_IAPEN BIT_TMP=EA;EA=0;TA=0xAA;TA=0x55;CHPCON |= SET_BIT0 ;EA=BIT_TMP
#define clr_IAPEN BIT_TMP=EA;EA=0;TA=0xAA;TA=0x55;CHPCON &= ~SET_BIT0;EA=BIT_TMP
#define set_APUEN BIT_TMP=EA;EA=0;TA=0xAA;TA=0x55;IAPUEN |= SET_BIT0 ;EA=BIT_TMP
#define clr_APUEN BIT_TMP=EA;EA=0;TA=0xAA;TA=0x55;IAPUEN &= ~SET_BIT0;EA=BIT_TMP
**********************************************************************************************/
void IAP_ERROR_LED(void)
{
while (1)
{
clr_P03;
Timer0_Delay1ms(100);
set_P03;
Timer0_Delay1ms(100);
}
}
//-----------------------------------------------------------------------------------------------------------/
void Trigger_IAP(void)
{
set_IAPGO; //trigger IAP
if((CHPCON&SET_BIT6)==SET_BIT6) // if fail flag is set, toggle error LED and IAP stop
{
clr_IAPFF;
IAP_ERROR_LED();
}
}
/*
WARNING:
No matter read or writer, when IAPFF is set 1,
this step process is fail. DATA should be ignore.
*/
//-----------------------------------------------------------------------------------------------------------/
/*****************************************************************************************************************
Erase APROM subroutine:
******************************************************************************************************************/
void Erase_LDROM(void)
{
UINT16 u16Count;
set_IAPEN; // Enable IAP function
IAPFD = 0xFF; // IMPORTANT !! To erase function must setting IAPFD = 0xFF
IAPCN = PAGE_ERASE_LD;
set_LDUEN; // APROM modify Enable
for(u16Count=0x0000;u16Count<DATA_SIZE/PAGE_SIZE;u16Count++) //
{
IAPAL = LOBYTE(u16Count*PAGE_SIZE + DATA_START_ADDR);
IAPAH = HIBYTE(u16Count*PAGE_SIZE + DATA_START_ADDR);
Trigger_IAP();
}
// clr_LDUEN;
// clr_IAPEN;
}
//-----------------------------------------------------------------------------------------------------------
void Erase_LDROM_Verify(void)
{
UINT16 u16Count;
set_IAPEN;
IAPAL = LOBYTE(DATA_START_ADDR);
IAPAH = HIBYTE(DATA_START_ADDR);
IAPCN = BYTE_READ_LD;
for(u16Count=0;u16Count<DATA_SIZE;u16Count++)
{
IAPFD = 0x00;
Trigger_IAP();
if(IAPFD != 0xFF)
IAP_ERROR_LED();
IAPAL++;
if(IAPAL == 0x00)
IAPAH++;
}
clr_IAPEN;
}
//-----------------------------------------------------------------------------------------------------------
void Program_LDROM(void)
{
UINT16 u16Count;
set_IAPEN;
set_LDUEN;
IAPAL = LOBYTE(DATA_START_ADDR);
IAPAH = HIBYTE(DATA_START_ADDR);
IAPCN = BYTE_PROGRAM_LD;
for(u16Count=0;u16Count<DATA_SIZE;u16Count++)
{
IAPFD++;
Trigger_IAP();
IAPAL++;
if(IAPAL == 0)
{
IAPAH++;
}
}
clr_LDUEN;
clr_IAPEN;
}
//-----------------------------------------------------------------------------------------------------------
void Program_LDROM_Verify(void)
{
UINT16 u16Count;
UINT8 u8Read_Data;
set_IAPEN;
IAPAL = LOBYTE(DATA_START_ADDR);
IAPAH = HIBYTE(DATA_START_ADDR);
IAPCN = BYTE_READ_LD;
u8Read_Data = 0x00;
for(u16Count=0;u16Count<DATA_SIZE;u16Count++)
{
Trigger_IAP();
if(IAPFD != u8Read_Data)
IAP_ERROR_LED();
IAPAL++;
if(IAPAL == 0)
{
IAPAH++;
}
u8Read_Data ++;
}
clr_IAPEN;
}
//-----------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------
void main (void)
{
Set_All_GPIO_Quasi_Mode;
//---------toggle GPIO1---------
clr_GPIO1;
Timer0_Delay1ms(100);
set_GPIO1;
Timer0_Delay1ms(100);
clr_GPIO1;
Timer0_Delay1ms(100);
set_GPIO1;
Timer0_Delay1ms(100);
//---------end toggle GPIO1---------
Erase_LDROM();
Erase_LDROM_Verify();
Program_LDROM();
Program_LDROM_Verify();
//---------toggle GPIO1---------
clr_GPIO1;
//---------end toggle GPIO1---------
while(1);
}
//-----------------------------------------------------------------------------------------------------------
N76E003_BSP_Keil_C51_V1.0.5\Sample_Code\IAP_AP-program-LD\IAP_APproLD.uvproj
这个例程演示的是在程序中(APPROM)编程 LDROM区域
用烧写器把LDROM读出来验证确实编程成功了!
在线
修改时钟校准值,实现串口115200bps通信DEMO。
离线
学习学习,刚好最近也在用这颗芯片
离线
最近比较火,取代003
离线
感觉这个芯片总体是挺好的,最大的坑就是无法全部IO口都能中断,只能最大8个管脚中断,还有模块没有独立时钟,AD采样不能独立分频,STM8其实还是无法取代的。
离线
感觉这个芯片总体是挺好的,最大的坑就是无法全部IO口都能中断,只能最大8个管脚中断,还有模块没有独立时钟,AD采样不能独立分频,STM8其实还是无法取代的。
总结到位!
离线
这个功能比stmf003强大的多又便宜,占了stm涨价的光
离线
用bsp包中例子PWM_Simple工程来测试,发现只有P01输出PWM,其他都没输出,晕哥有遇到这个情况么?
离线
在线
参考了一个台湾同胞的指导文章,用sdcc来编译,结果就只有一路正常。:/
使用SDCC開發新唐N76E003 1T 8051
集成sdcc&makefile
离线
建议先走正路,然后再摸石头过河
离线
2.0版本相关工具有bug, 下载最新的工具集试一试:
https://www.nuvoton.com/hq/support/tool-and-software/software/development-tool/?__locale=en
http://www.nuvoton.com/resource-files/Nu-Link_Keil_Driver_V2.05.6815.zip
http://www.nuvoton.com/resource-files/NuMicro_ICP_Programming_Tool_V2.05.6815.zip
更新软件会强制刷新 NU-LINK, 由于新唐升级机制问题,很容易 变砖, 小心操作。
在线
START.A51:
$INCLUDE (N76E003.INC)
;******************************************************************************
; This code illustrates how to use IAP to make APROM 201h as a byte of
; Data Flash when user code is executed in APROM.
;******************************************************************************
ALL_ERASE_CONFIG EQU 11100010b
BYTE_PROGRAM_CONFIG EQU 11100001b
BYTE_READ_CONFIG EQU 11000000b
ORG 0000h
CALL Enable_IAP
CALL Read_CONFIG ;read back CONFIG2
CALL Disable_IAP
SJMP $
Enable_IAP:
MOV TA,#0Aah ;CHPCON is TA protected
MOV TA,#55h
ORL CHPCON,#00000001b ;IAPEN = 1, enable IAP mode
RET
Disable_IAP:
MOV TA,#0Aah
MOV TA,#55h
ANL CHPCON,#11111110b ;IAPEN = 0, disable IAP mode
RET
Read_CONFIG:
MOV IAPCN,#BYTE_READ_CONFIG
MOV IAPAH,#00h
MOV IAPAL,#00h
CALL Trigger_IAP
MOV R3,IAPFD
MOV IAPAL,#01h
CALL Trigger_IAP
MOV R4,IAPFD
MOV IAPAL,#02h
CALL Trigger_IAP
MOV R5,IAPFD
MOV IAPAL,#03h
CALL Trigger_IAP
MOV R6,IAPFD
MOV IAPAL,#04h
CALL Trigger_IAP
MOV R7,IAPFD
RET
Trigger_IAP:
MOV TA,#0Aah ;IAPTRG is TA protected
MOV TA,#55h
ORL IAPTRG,#00000001b ;write ‘1’ to IAPGO to trigger IAP process
RET
END
N76E003.INC:
RCTRIM0 EQU 0x84;
RCTRIM1 EQU 0x85;
RWK EQU 0x86;
CKCON EQU 0x8E;
WKCON EQU 0x8F;
SFRS EQU 0x91; //TA Protection
CAPCON0 EQU 0x92;
CAPCON1 EQU 0x93;
CAPCON2 EQU 0x94;
CKDIV EQU 0x95;
CKSWT EQU 0x96; //TA Protection
CKEN EQU 0x97; //TA Protection
SBUF_1 EQU 0x9A;
EIE EQU 0x9B;
EIE1 EQU 0x9C;
CHPCON EQU 0x9F; //TA Protection
AUXR1 EQU 0xA2;
BODCON0 EQU 0xA3; //TA Protection
IAPTRG EQU 0xA4; //TA Protection
IAPUEN EQU 0xA5; //TA Protection
IAPAL EQU 0xA6;
IAPAH EQU 0xA7;
SADDR EQU 0xA9;
WDCON EQU 0xAA; //TA Protection
BODCON1 EQU 0xAB; //TA Protection
P3M1 EQU 0xAC;
P3S EQU 0xAC; //Page1
P3M2 EQU 0xAD;
P3SR EQU 0xAD; //Page1
IAPFD EQU 0xAE;
IAPCN EQU 0xAF;
P0M1 EQU 0xB1;
P0S EQU 0xB1; //Page1
P0M2 EQU 0xB2;
P0SR EQU 0xB2; //Page1
P1M1 EQU 0xB3;
P1S EQU 0xB3; //Page1
P1M2 EQU 0xB4;
P1SR EQU 0xB4; //Page1
P2S EQU 0xB5;
IPH EQU 0xB7;
PWMINTC EQU 0xB7; //Page1
SADEN EQU 0xB9;
SADEN_1 EQU 0xBA;
SADDR_1 EQU 0xBB;
I2DAT EQU 0xBC;
I2STAT EQU 0xBD;
I2CLK EQU 0xBE;
I2TOC EQU 0xBF;
I2CON EQU 0xC0;
I2ADDR EQU 0xC1;
ADCRL EQU 0xC2;
ADCRH EQU 0xC3;
T3CON EQU 0xC4;
PWM4H EQU 0xC4; //Page1
RL3 EQU 0xC5;
PWM5H EQU 0xC5; //Page1
RH3 EQU 0xC6;
PIOCON1 EQU 0xC6; //Page1
TA EQU 0xC7;
T2CON EQU 0xC8;
T2MOD EQU 0xC9;
RCMP2L EQU 0xCA;
RCMP2H EQU 0xCB;
TL2 EQU 0xCC;
PWM4L EQU 0xCC; //Page1
TH2 EQU 0xCD;
PWM5L EQU 0xCD; //Page1
ADCMPL EQU 0xCE;
ADCMPH EQU 0xCF;
PWMPH EQU 0xD1;
PWM0H EQU 0xD2;
PWM1H EQU 0xD3;
PWM2H EQU 0xD4;
PWM3H EQU 0xD5;
PNP EQU 0xD6;
FBD EQU 0xD7;
PWMCON0 EQU 0xD8;
PWMPL EQU 0xD9;
PWM0L EQU 0xDA;
PWM1L EQU 0xDB;
PWM2L EQU 0xDC;
PWM3L EQU 0xDD;
PIOCON0 EQU 0xDE;
PWMCON1 EQU 0xDF;
ADCCON1 EQU 0xE1;
ADCCON2 EQU 0xE2;
ADCDLY EQU 0xE3;
C0L EQU 0xE4;
C0H EQU 0xE5;
C1L EQU 0xE6;
C1H EQU 0xE7;
ADCCON0 EQU 0xE8;
PICON EQU 0xE9;
PINEN EQU 0xEA;
PIPEN EQU 0xEB;
PIF EQU 0xEC;
C2L EQU 0xED;
C2H EQU 0xEE;
EIP EQU 0xEF;
CAPCON3 EQU 0xF1;
CAPCON4 EQU 0xF2;
SPCR EQU 0xF3;
SPCR2 EQU 0xF3; //Page1
SPSR EQU 0xF4;
SPDR EQU 0xF5;
AINDIDS EQU 0xF6;
EIPH EQU 0xF7;
SCON_1 EQU 0xF8;
PDTEN EQU 0xF9; //TA Protection
PDTCNT EQU 0xFA; //TA Protection
PMEN EQU 0xFB;
PMD EQU 0xFC;
EIP1 EQU 0xFE;
EIPH1 EQU 0xFF;
从手册里面扣了几行代码, 读 N76E003 的配置 CONFIG 0 .. 4
在线
$INCLUDE (N76E003.INC)
;******************************************************************************
; This code illustrates how to use IAP to make APROM 201h as a byte of
; Data Flash when user code is executed in APROM.
;******************************************************************************
ALL_ERASE_CONFIG EQU 11100010b
BYTE_PROGRAM_CONFIG EQU 11100001b
BYTE_READ_CONFIG EQU 11000000b
ORG 0000h
CALL Enable_IAP
CALL Read_CONFIG ;read back CONFIG2
CALL Enable_CONFIG_Update
CALL Erase_CONFIG ;erase CONFIG bytes
CALL Program_CONFIG ;programming CONFIG2 with new data
CALL Disable_CONFIG_Update
CALL Program_CONFIG_Verify ;verify Programmed CONFIG2
CALL Read_CONFIG ;read back CONFIG2
CALL Disable_IAP
SJMP $
Enable_IAP:
MOV TA,#0Aah ;CHPCON is TA protected
MOV TA,#55h
ORL CHPCON,#00000001b ;IAPEN = 1, enable IAP mode
RET
Disable_IAP:
MOV TA,#0Aah
MOV TA,#55h
ANL CHPCON,#11111110b ;IAPEN = 0, disable IAP mode
RET
Read_CONFIG:
MOV IAPCN,#BYTE_READ_CONFIG
MOV IAPAH,#00h
MOV IAPAL,#00h
CALL Trigger_IAP
MOV R3,IAPFD
MOV IAPAL,#01h
CALL Trigger_IAP
MOV R4,IAPFD
MOV IAPAL,#02h
CALL Trigger_IAP
MOV R5,IAPFD
MOV IAPAL,#03h
CALL Trigger_IAP
MOV R6,IAPFD
MOV IAPAL,#04h
CALL Trigger_IAP
MOV R7,IAPFD
RET
Trigger_IAP:
MOV TA,#0Aah ;IAPTRG is TA protected
MOV TA,#55h
ORL IAPTRG,#00000001b ;write ‘1’ to IAPGO to trigger IAP process
RET
Enable_CONFIG_Update:
MOV TA,#0Aah
MOV TA,#55h
ORL IAPUEN,#00000100b ;CFUEN = 1, enable CONFIG update
RET
Disable_CONFIG_Update:
MOV TA,#0Aah
MOV TA,#55h
ANL IAPUEN,#11111011b ;CFUEN = 0, disable CONFIG update
RET
;********************************************************************
; IAP CONFIG Function
;********************************************************************
Erase_CONFIG:
MOV IAPCN,#ALL_ERASE_CONFIG
MOV IAPAH,#00h
MOV IAPAL,#00h
MOV IAPFD,#0FFh
CALL Trigger_IAP
RET
Program_CONFIG:
MOV IAPCN,#BYTE_PROGRAM_CONFIG
MOV IAPAH,#00h
MOV IAPAL,#02h
MOV A,R7
ANL A,#11111011b
MOV IAPFD,A ;disable BOD reset
MOV R6,A ;temp data
CALL Trigger_IAP
RET
Program_CONFIG_Verify:
MOV IAPCN,#BYTE_READ_CONFIG
MOV IAPAH,#00h
MOV IAPAL,#02h
CALL Trigger_IAP
MOV B,R6
MOV A,IAPFD
CJNE A,B,Program_CONFIG_Verify_Error
RET
Program_CONFIG_Verify_Error:
CALL Disable_IAP
MOV P0,#00h
SJMP $
END
写 N76E003 的 CONFIG2 成功
$INCLUDE (N76E003.INC)
;******************************************************************************
; This code illustrates how to use IAP to make APROM 201h as a byte of
; Data Flash when user code is executed in APROM.
;******************************************************************************
ALL_ERASE_CONFIG EQU 11100010b
BYTE_PROGRAM_CONFIG EQU 11100001b
BYTE_READ_CONFIG EQU 11000000b
ORG 0000h
CALL Enable_IAP
CALL Read_CONFIG ;read back CONFIG2
CALL Enable_CONFIG_Update
CALL Erase_CONFIG ;erase CONFIG bytes
CALL Program_CONFIG ;programming CONFIG2 with new data
CALL Disable_CONFIG_Update
CALL Program_CONFIG_Verify ;verify Programmed CONFIG2
CALL Read_CONFIG ;read back CONFIG2
CALL Disable_IAP
SJMP $
Enable_IAP:
MOV TA,#0Aah ;CHPCON is TA protected
MOV TA,#55h
ORL CHPCON,#00000001b ;IAPEN = 1, enable IAP mode
RET
Disable_IAP:
MOV TA,#0Aah
MOV TA,#55h
ANL CHPCON,#11111110b ;IAPEN = 0, disable IAP mode
RET
Read_CONFIG:
MOV IAPCN,#BYTE_READ_CONFIG
MOV IAPAH,#00h
MOV IAPAL,#00h
CALL Trigger_IAP
MOV R3,IAPFD
MOV IAPAL,#01h
CALL Trigger_IAP
MOV R4,IAPFD
MOV IAPAL,#02h
CALL Trigger_IAP
MOV R5,IAPFD
MOV IAPAL,#03h
CALL Trigger_IAP
MOV R6,IAPFD
MOV IAPAL,#04h
CALL Trigger_IAP
MOV R7,IAPFD
RET
Trigger_IAP:
MOV TA,#0Aah ;IAPTRG is TA protected
MOV TA,#55h
ORL IAPTRG,#00000001b ;write ‘1’ to IAPGO to trigger IAP process
RET
Enable_CONFIG_Update:
MOV TA,#0Aah
MOV TA,#55h
ORL IAPUEN,#00000100b ;CFUEN = 1, enable CONFIG update
RET
Disable_CONFIG_Update:
MOV TA,#0Aah
MOV TA,#55h
ANL IAPUEN,#11111011b ;CFUEN = 0, disable CONFIG update
RET
;********************************************************************
; IAP CONFIG Function
;********************************************************************
Erase_CONFIG:
MOV IAPCN,#ALL_ERASE_CONFIG
MOV IAPAH,#00h
MOV IAPAL,#00h
MOV IAPFD,#0FFh
CALL Trigger_IAP
RET
Program_CONFIG:
MOV IAPCN,#BYTE_PROGRAM_CONFIG
MOV IAPAH,#00h
MOV IAPAL,#00h
MOV A,R7
ANL A,#6Fh
MOV IAPFD,A ;disable BOD reset
MOV R6,A ;temp data
CALL Trigger_IAP
MOV IAPAL,#01h
MOV A,R7
ANL A,#0FBh
MOV IAPFD,A ;disable BOD reset
MOV R6,A ;temp data
CALL Trigger_IAP
MOV IAPAL,#02h
MOV A,R7
ANL A,#0FBh
MOV IAPFD,A ;disable BOD reset
MOV R6,A ;temp data
CALL Trigger_IAP
RET
Program_CONFIG_Verify:
MOV IAPCN,#BYTE_READ_CONFIG
MOV IAPAH,#00h
MOV IAPAL,#02h
CALL Trigger_IAP
MOV B,R6
MOV A,IAPFD
CJNE A,B,Program_CONFIG_Verify_Error
RET
Program_CONFIG_Verify_Error:
CALL Disable_IAP
MOV P0,#00h
SJMP $
END
写三个CONFIG寄存器成功.
在线
这个单片机性价比好,mark
离线
乐趣在于折腾,sdcc编译问题已解决。
原因是sdcc编译|=运算的时候会编译出3条指令,而对于某些受写保护SFR,打开TA保护后只有4个时钟周期是可以写的。
解决方法是通过peep-file来做指令替换,测试pwm例子已正常。集成sdcc&makefile
keil c51编译结果
mov TA, #0xAA ; TA = 0xAA
mov TA, #0x55 ; TA = 0x55 {'U'}
orl SFRS, #0x01 ; SFRS |= 0x01
未修正前SDCC编译结果
mov TA, #0xAA ; TA = 0xAA
mov TA, #0x55 ; TA = 0x55 {'U'}
mov R6, SFRS ; R6 = SFRS
orl 0x06, #0x01 ; 0x06 |= 0x01
mov SFRS, R6 ; SFRS = R6
离线
乐趣在于折腾,sdcc编译问题已解决。
原因是sdcc编译|=运算的时候会编译出3条指令,而对于某些受写保护SFR,打开TA保护后只有4个时钟周期是可以写的。
解决方法是通过peep-file来做指令替换,测试pwm例子已正常。集成sdcc&makefilekeil c51编译结果
mov TA, #0xAA ; TA = 0xAA mov TA, #0x55 ; TA = 0x55 {'U'} orl SFRS, #0x01 ; SFRS |= 0x01
未修正前SDCC编译结果
mov TA, #0xAA ; TA = 0xAA mov TA, #0x55 ; TA = 0x55 {'U'} mov R6, SFRS ; R6 = SFRS orl 0x06, #0x01 ; 0x06 |= 0x01 mov SFRS, R6 ; SFRS = R6
我比较了一下源码:
就 Common.c 多了一个函数:
unsigned char
_sdcc_external_startup (void)
{
__asm
mov 0xC7, #0xAA ; [0xC7] = 0xAA
mov 0xC7, #0x55 ; [0xC7] = 0x55 {'U'}
mov 0xFD, #0x5A ; [0xFD] = 0x5A {'Z'}
mov 0xC7, #0xAA ; [0xC7] = 0xAA
mov 0xC7, #0x55 ; [0xC7] = 0x55 {'U'}
mov 0xFD, #0xA5 ; [0xFD] = 0xA5
__endasm;
return 0;
}
请问这个是解决什么问题呢?
离线
原来是 Makefile
CFLAGS = -I./inc -I$(INCDIR) -m$(MCU_MODEL) --model-$(MODEL) --out-fmt-ihx --no-xinit-opt $(DEBUG) -DFOSC_160000 --peep-filetools/peep.def
tools\peep.def 这个的作用哦
replace {
mov %1,%2
orl a%1,%3
mov %2,%1
} by {
orl %2,%3
}
遇到上面三条指令, 就替换成下面一条指令, 真牛人也, 这个问题都能找出来!
离线
以下为是写时效保护寄存器的正确和错误范例:
Example 1,
MOV TA,#0AAH ;3 clock cycles
MOV TA,#55H ;3 clock cycles
ORL WDCON,#data ;4 clock cyclesExample 2,
MOV TA,#0AAH ;3 clock cycles
MOV TA,#55H ;3 clock cycles
NOP ;1 clock cycle
ANL BODCON0,#data ;4 clock cyclesExample 3,
MOV TA,#0AAH ;3 clock cycles
MOV TA,#55H ;3 clock cycles
MOV WDCON,#data1 ;3 clock cycles
ORL BODCON0,#data2 ;4 clock cyclesExample 4,
MOV TA,#0AAH ;3 clock cycles
NOP ;1 clock cycle
MOV TA,#55H ;3 clock cycles
ANL BODCON0,#data ;4 clock cycles在第一个例子中,写保护位在三个时钟周期窗口关闭之前完成。然而,在例2中,BODCON0的写入并
没有在时效访问窗口打开时完成,操作完这些指令后,BODCON0的值不会有变化。示例3中,WDCON
写入成功,但对BODCON0访问超过三个机器周期窗口,因此BODCON0值不会改变。例4,第二次写
55H对应第一个AAH写入时间超过了3个机器周期,时效访问窗口打开失败,所以后面的写入全部无效。
新唐这寄存器保护也是到位
离线
@jimmy
_sdcc_external_startup会在启动后调用,里面可以做一些初始化的操作,其中的汇编是直接从keil n76e003 bsp的启动文件里面扣出来的,作用是关闭POR功能
离线
@skcks 感谢分享! 有空试一试 sdcc, 对了, 可以使用 NU-LINK 单步调试吗?
sdcc用不了NU-LINK,坐等大神逆向开发出解决方案
离线
@jimmy
_sdcc_external_startup会在启动后调用,里面可以做一些初始化的操作,其中的汇编是直接从keil n76e003 bsp的启动文件里面扣出来的,作用是关闭POR功能
翻了一下手册, 涨知识了:
重要说明:
由于N76E003 POR侦测电压落在1.3V 至 1.5 V范围IE之间,当N76E003进入掉电模式后,再次唤醒
时,N76E003的内核电压可能低于1.5 V,此时可能会触发POR 动作,造成芯片复位。为避免这种现
象,建议当每次电源上电正常运行程序之后,关闭POR模块。解决方法:
由于POR是用于判断VDD上电状态,当上电状态结束后由LVR来判断电源状态,故建议当稳定上电后,
关闭POR,下面说明如何关闭POR功能。
寄存器PORDIS(FDH)可以用于关闭POR功能。关闭POR
对PORDIS寄存器先写入5AH,再写入A5H可以关闭POR功能请严格按照如下步骤关闭POR功能:
sfr PORDIS = 0XFD; TA =0XAA; TA= 0X55; PORDIS = 0X5A; TA=0XAA; TA=0X55; PORDIS = 0XA5;
离线
晕哥 说:@skcks 感谢分享! 有空试一试 sdcc, 对了, 可以使用 NU-LINK 单步调试吗?
sdcc用不了NU-LINK,坐等大神逆向开发出解决方案
这个可以有, 但是受众还是太小, 玩51的本来就少了, 玩SDCC的就真凤毛麟角.
离线
#include "N76E003.h"
#include "Common.h"
#include "Delay.h"
#include "SFR_Macro.h"
#include "Function_define.h"
#define T1_INIT 670
UINT8 u8TH0_Tmp,u8TL0_Tmp,u8TH1_Tmp,u8TL1_Tmp;
UINT16 t = 0;
/************************************************************************************************************
* TIMER 1 interrupt subroutine
************************************************************************************************************/
void Timer1_ISR (void) interrupt 3 //interrupt address is 0x001B
{
TH1 = u8TH1_Tmp;
TL1 = u8TL1_Tmp;
t++;
//P15 = ~P15; //P0.3 toggle when interrupt
}
/************************************************************************************************************
* Main function
************************************************************************************************************/
void main (void)
{
Set_All_GPIO_Quasi_Mode;
TIMER1_MODE1_ENABLE;
clr_T1M;
u8TH1_Tmp = (65535-T1_INIT)/256;
u8TL1_Tmp = (65535-T1_INIT)%256;
TH1 = u8TH1_Tmp;
TL1 = u8TL1_Tmp;
set_ET1; //enable Timer1 interrupt
set_EA; //enable interrupts
t = 0;
set_TR1; //Timer1 run
while(1)
{
if (t >= 2000)
{
clr_TR1;
t = 0;
P15 = ~P15; //P1.5 toggle when interrupt
set_TR1;
}
}
}
几行代码搞定 一个 1秒翻转 IO 的Demo
离线
离线
16Mhz 下明明 9600bps 和 38400bps 的误差率是一致,
但是两个批次的N76E003, 有一个批次上面两个波特率正常,
有一个批次,38400bsp 不正常, 而9600bps 正常.
void MODIFY_HIRC_166(void) // Modify HIRC to 16.6MHz, more detail please see datasheet V1.02
{
UINT8 hircmap0,hircmap1;
UINT16 trimvalue16bit;
/* Check if power on reset, modify HIRC */
if ((PCON&SET_BIT4)==SET_BIT4)
{
hircmap0 = RCTRIM0;
hircmap1 = RCTRIM1;
trimvalue16bit = ((hircmap0<<1)+(hircmap1&0x01));
trimvalue16bit = trimvalue16bit - 15;
hircmap1 = trimvalue16bit&0x01;
hircmap0 = trimvalue16bit>>1;
TA=0XAA;
TA=0X55;
RCTRIM0 = hircmap0;
TA=0XAA;
TA=0X55;
RCTRIM1 = hircmap1;
/* Clear power on flag */
PCON &= CLR_BIT4;
}
}
void main (void)
{
UINT8 c;
MODIFY_HIRC_166();
set_CLOEN; //Check HIRC out wavefrom to confirm the HIRC modified
InitialUART0_Timer1(38400);
while(1)
{
if(RI)
{
c = SBUF;
RI = 0;
Send_Data_To_UART0(c);
}
}
}
修正到 16.6Mhz, 两个波特率都正常了。
在线
添加一个管脚中断程序, 用 P1 这组口, 引脚需要上拉, 可以从掉电模式唤醒,电流未测。
源码下载: Pin_Interrupt_20190715.7z
bit PIFlag;//管脚中断标志位
sbit LED=P1^5;
void main (void)
{
Set_All_GPIO_Quasi_Mode;
//设置为输入模式
P10_Input_Mode;
P11_Input_Mode;
P12_Input_Mode;
clr_PIPS1;
set_PIPS0;//选择P1为中断输入源
//Enable_BIT1_HighLevel_Trig; //高电平触发管脚中断
//Enable_BIT1_FallEdge_Trig; //下降沿
//Enable_BIT1_RasingEdge_Trig;//上升沿
Enable_BIT2_LowLevel_Trig;
Enable_BIT1_LowLevel_Trig; //低电平
Enable_BIT0_LowLevel_Trig;
LED=1;//初始化LED端口
Timer0_Delay1ms(20);
set_EPI;//开启管脚中断使能
EA = 1;//开启总中断
while(1)
{
if(PIFlag)//判定是否溢出
{
LED=0;
Timer0_Delay1ms(10);
LED=1;//灯闪烁
PIFlag=0;
ADCCON1 = 0X00;//关闭ADC
clr_BODEN;//关闭欠压检测
set_PD;// 进入掉电模式
}
}
}
//-------管脚中断中断服务程序---------
void PinInterrupt (void) interrupt 7
{
if((PIF & 0x01) == 0x01)//P10位于 0通道
{
PIF=0;//清除外部中断标志
PIFlag=1;
}
else if((PIF & 0x02) == 0x02)//P11位于 1通道
{
PIF=0;//清除外部中断标志
PIFlag=1;
}
else if((PIF & 0x04) == 0x04)//P12位于 2通道
{
PIF=0;//清除外部中断标志
PIFlag=1;
}
}
在线
乐趣在于折腾,sdcc编译问题已解决。
原因是sdcc编译|=运算的时候会编译出3条指令,而对于某些受写保护SFR,打开TA保护后只有4个时钟周期是可以写的。
解决方法是通过peep-file来做指令替换,测试pwm例子已正常。集成sdcc&makefilekeil c51编译结果
mov TA, #0xAA ; TA = 0xAA mov TA, #0x55 ; TA = 0x55 {'U'} orl SFRS, #0x01 ; SFRS |= 0x01
未修正前SDCC编译结果
mov TA, #0xAA ; TA = 0xAA mov TA, #0x55 ; TA = 0x55 {'U'} mov R6, SFRS ; R6 = SFRS orl 0x06, #0x01 ; 0x06 |= 0x01 mov SFRS, R6 ; SFRS = R6
在Github上看到了大佬的解决方案被引用了!上面的另一个解决方案感觉也不错。P.s:关闭POR有种MSP430关闭看门狗的既视感wkaster/N76E003: Nuvoton N76E003 with SDCC
最近编辑记录 WeilunFong (2020-01-18 21:25:30)
离线
跟着晕哥努力学习~
离线
晕哥试过bootloader改成串口1么?有没任何资料说过串口1不能做isp?
离线
如果用自己的ISP上位机软件,哪个口可以做ISP吧,i2c,spi都行。
因为串口1复用了icp的管脚,结果改了发现怎么也发不出数据,还未确定是软件问题还是硬件问题。
离线
搬运了貌似是官方放出的串口烧写的BootLoader到串口1,改成SDCC编译了,上机位要求python3。官方代码乱得一坨,保持了原汁原味,终于可以在macOS下刷程序。
isp_uart1.zip
貌似是官方放出的Nuvoton Standard ISP Code_N76E003.zip
最近编辑记录 skcks (2020-04-08 15:16:51)
离线
搬运了貌似是官方放出的串口烧写的BootLoader到串口1,
离线
P1.1死活不能输入, 发现是开了使能时钟输出 set_CLOEN
把这个代码屏蔽就好了。
离线
SDCC其实蛮好用的,编译速度很快,特别是linux环境下,windows下面速度也挺快。用好SDCC需要一些技巧,比如你得比较熟悉makefile,以及SDCC里面的一些小坑。我个人做的很多项目都是使用SDCC,除了51单片机外,SDCC也支持STM8的。下面我分享一个新塘单片机的工程文件给大家参考一下
NE76003_SDCC_UART_TEST_20200518-1515.rar
最近编辑记录 yushikong (2020-05-18 15:16:41)
离线
编辑环境是windows加eclipse,下面分享几张截图,
这一张是关于下载程序到单片机里面的配置,稍微等待一下就能下载了,不过不支持在线调试,我一般使用串口直接调试,不怎么用在线调试。
下面说一说eclipse对比keil的优势,其实最主要的是编辑代码的增强,keil特别是C51版本的,基本还停留在上世纪的编辑风格,和windows自带的记事本强不了多少。eclipse具有代码提示、关键词特殊颜色、全局修改变量等等功能,也可以直接搭配git
SDCC时至今日还在活跃的更新,说明还是有一部分人在用的。SDCC里面的一个大坑是关于中断函数,据我个人测试中断函数必须在main函数之前被声明或者直接编写,不然就无法进中断,切记。SDCC编译固件时如果工程里面有较多的无用代码,它也会直接编译到hex里面的,这个问题困扰了我好久,一直没有得到解决。所以如果空间紧张,建议注释掉一些无关的代码,避免代码空间膨胀
最近编辑记录 yushikong (2020-05-18 15:36:14)
离线
这里补充一下下载程序的命令,其实很简单,就两行代码
D:\eclipse_sdcc\Nuvoton_Tools\NuLink_Command_Tool\NuLink.exe -e APROM
D:\eclipse_sdcc\Nuvoton_Tools\NuLink_Command_Tool\NuLink.exe -w APROM %1
有问题的话可以大家一起交流一下
离线
编辑环境是windows加eclipse,下面分享几张截图,
https://whycan.cn/files/members/394/none.png 这一张是关于下载程序到单片机里面的配置,稍微等待一下就能下载了,不过不支持在线调试,我一般使用串口直接调试,不怎么用在线调试。下面说一说eclipse对比keil的优势,其实最主要的是编辑代码的增强,keil特别是C51版本的,基本还停留在上世纪的编辑风格,和windows自带的记事本强不了多少。eclipse具有代码提示、关键词特殊颜色、全局修改变量等等功能,也可以直接搭配git
SDCC时至今日还在活跃的更新,说明还是有一部分人在用的。SDCC里面的一个大坑是关于中断函数,据我个人测试中断函数必须在main函数之前被声明或者直接编写,不然就无法进中断,切记。SDCC编译固件时如果工程里面有较多的无用代码,它也会直接编译到hex里面的,这个问题困扰了我好久,一直没有得到解决。所以如果空间紧张,建议注释掉一些无关的代码,避免代码空间膨胀
关于中断这个当初我也是被坑了好久,后来才发现这个其所在sdcc的手册内是有描诉的,看他的意思除了能放在main对应的那个c文件内,在main的头文件包含也是可以的,不过后面那个场景我没试过。
SDCC allows interrupt service routines to be coded in C, with some extended keywords.
void timer_isr (void) __interrupt (1) __using (1)
{
...
}
The optional number following the __interrupt keyword is the interrupt number this routine will service. When
present, the compiler will insert a call to this routine in the interrupt vector table for the interrupt number specified.
If you have multiple source files in your project, interrupt service routines can be present in any of them, but a
prototype of the isr MUST be present or included in the file that contains the function main. The optional (8051
specific) keyword __using can be used to tell the compiler to use the specified register bank when generating code
for this function.
离线
@yushikong 感谢大佬分享, eclipse + sdcc 这个不错, 但这样调试恐怕不方便了吧?
一般是直接下载程序,重启后看串口信息,或者硬件提示比如数码管、LED灯等,习惯就好
离线
关于中断这个当初我也是被坑了好久,后来才发现这个其所在sdcc的手册内是有描诉的,看他的意思除了能放在main对应的那个c文件内,在main的头文件包含也是可以的,不过后面那个场景我没试过。
SDCC allows interrupt service routines to be coded in C, with some extended keywords.
void timer_isr (void) __interrupt (1) __using (1)
{
...
}
The optional number following the __interrupt keyword is the interrupt number this routine will service. When
present, the compiler will insert a call to this routine in the interrupt vector table for the interrupt number specified.
If you have multiple source files in your project, interrupt service routines can be present in any of them, but a
prototype of the isr MUST be present or included in the file that contains the function main. The optional (8051
specific) keyword __using can be used to tell the compiler to use the specified register bank when generating code
for this function.
嗯,我一般是直接写一个头文件和源文件包含全部的中断, 这样我感觉会好一些,在芯片的头文件中包含一下即可
最近编辑记录 yushikong (2020-05-18 17:24:17)
离线
转载: https://www.cnblogs.com/jikexianfeng/p/11024001.html
#include <N76E003.H>
#include <SFR_Macro.h>
#include <Function_Define.h>
bit BIT_TMP; // 调用 SFR_Macro.h 使用的
void main(void){
// 开通外部
set_EXTEN1;
set_EXTEN0;
// 等待外部稳定
while(!(CKSWT|0x08));
// 选择外部时钟
clr_OSC1;
set_OSC0;
// 等待外部时钟切换成功
while(CKEN&0x01);
while(1){
; // 函数主题
}
}
离线