1 前言
1.1 本文适合不懂eclipse的开发者,由于所有东西都是开源的,所以你只需百度一下那些软件的名字就可以去它的官网里下载他们的最新版本了
1.2 重要提示:这篇文章的前后关联性很强,比如:你想建立32的标准库版工程可能会涉及建立32的寄存器版工程的内容,所以我这边也提供了一个很详细的目录给你进行手动跳转
2 Eclipse的安装与开发java:
首先是eclipse的安装,eclipse是用Java开发的,所以运行它需要安装jdk,jdk官网(https://www.oracle.com/java/technologies/javase-downloads.html)
eclipse官网(https://www.eclipse.org/downloads/),里面下载是可以选择中国的镜像源
安装JDK(一直点下一步,安装目录就默认就行了),安装好后配置环境变量
如上图,新建一个(JAVA_HOME)变量,后面的值填入刚刚JDK的安装目录,如果默认安装目录就是(C:\Program Files\Java\jdk-13.0.2)
如上图,新建一个(CLASSPATH)变量,后面的值填(.;%JAVA_HOME%\lib)
双击Path,然后点新建,值为输入(%JAVA_HOME%\bin),如上下两图
安装eclipse:解压下载的eclipse软件压缩包到你想要的地方,打开解压后文件夹,双击下图程序
上图是设置你的工作区,就是设置放你新建的项目的文件的路径,可以把下面的那个选项勾上,就是默认就是用这个路径,下次打开eclipse时不再弹出这个窗口询问你。
然后就是上图这个界面,可以把welcome页删掉,删不删随你。
到现在为止,你已经可以编写Java程序了,怎么建Java的项目,还请您百度一下,因为我对Java的项目也还不太了解。转载一个百度的经验贴给你:https://jingyan.baidu.com/article/c85b7a64aedf74003bac95e0.html
3 Eclipse开发32单片机的配置(以stm32f103c8t6为例子):
3.1 软件安装部分:
首先要在eclipse里下载cdt插件,进行下图操作
点击上图的位置打开eclipse marketplace,然后搜索cdt
如上图,点击第一个的右下角安装
上图界面点确认,加载完后选择我接受…,再点完成,然后等待下载安装,这个时间会比较长,你可以干点别的事情来等待。
想看下载进度的话可以点击下图右下角的红圈的那个部分弹出上图这个点现在重启软件,重启软件后就安装完成了。
重启后再点击上图这个,再单击右上角的管理,如下图再把cdt前面的选项勾上,后点应用并关闭,如下图
在点击上图的红圈处,选cdt
勾上cdt main features的选项,就点击下一步,再下一步,选接受后点完成,由于和上面的那个安装操作差不多就不截图了。继续等待安装完成,时间也是比较长的。弹出重启软件就选重启就OK了。
然后继续打开eclipse marketplace,如上图,这次搜索 gnu mcu eclipse
继续像之前那样安装它,里面的东西都默认选好的了,没啥特别的我就不截图了。
安装这个的过程中会出现这个,点击install anyway
然后就是下载MCU Packages,这里如果我把我直接下载好的压缩包发出来让大家下载,百度云链接:链接:https://pan.baidu.com/s/1oAYqwAa0t_j6m7Jm7NitBw
提取码:gane,下载完后把它解压到你喜欢的地方(最好没有中文的路径,我没试过有中文的行不行),再在eclipse里设置MCU Packages的路径,进行下图操作
在packages folder里选中刚刚解压的mcu packages的位置,如下图
再点应用且关闭,然后点击下图中的红圈的位置
然后就会弹出下图的内容,如果没弹出,那么请你再三检查一下刚刚的那个mcu packages的路径有没有设置正确,如果实在是设置正确了没有出下面的内容,就点击一下下图的红圈位置
它就会帮你刷新包了,它可能会弹出一些错误,选择忽略全部就好了,值得一提的是如果你真的是整个下载这个包的话,是需要VPN的,没有VPN不单单是速度慢的问题,是简直就是下载不了,不过不要担心,如果你真的把上边的包的路径设置正确但没有显示这个里的内容的话那个是不需要VPN的,因为里面的已经内容有了的话它检索出来就不会去再请求下载了,它会弹出那些错误报告也是正常的(因为我这边完整的mcu packages也会弹出)直接选忽略全部。
在内容中往下滑,在keil一大类里面,你会发现这个F1和F4的包的颜色和其他的都不一样,因为两个mcu包是我帮你安装好的了(如果你是设置好了之前我给你的mcu packages的压缩包的话),然后你如果是开发stm32F1和F4系列的话就不用再进行这个包的安装了,但如果你是想开发别的单片机,比如stm32F3系列的,就先展开F3的包,右击最新的版本,然后点安装,这个下载可能会比较慢,不过没办法。这个mcu packages的用途嘛我感觉就是在调试的时候用来查看外设寄存器的数据和提供该系列mcu的HAL库模板的(我只是瞎猜的),还有什么其他的用途的话我就还没摸透,应该作用挺大的吧。
然后就是进行编译链的安装,这里给出gcc-arm的官网(https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm),下载在下图位置
双击下载好的下图编译工具
然后就是:OK>>下一步>>我接受>>安装>>在安装完成的界面中选中Add path…选项>>再点击完成。如下图。
再是安装构建工具,这个工具的安装目录比较特殊,一定要跟着步骤来,并且在此提供下载链接(点击这里下载构建工具压缩包),如果那个链接要积分的话(我本来是没设置要积分的),就到这个百度云链接下载(链接:https://pan.baidu.com/s/1LZSr8skNVEfhqQW3R2QFJA
提取码:xvn0)。说明:其实它就是一个make工具,这个是和gnu mcu eclipse插件配套的,不过你用别的make工具也是可以的。
然后把解压得到的文件夹放到下图目录中,注意目录别放错
放好了就重启一下eclipse,然后打开eclipse的windows>>preferences>>MCU的下图
你会发现build tool的路径就是刚刚的那个压缩包的路径(这代表安装成功了),如果没有这个路径,那么你那个压缩包可能放错位置了。
然后配置一下eclipse让它可以在file>>new里面创建c项目
点击上图的自定义偏好,在按下面的操作把该勾的勾上
下边开始创建工程,分成寄存器版和标准库版,给出寄存器版的原因是寄存器版是最最最基本的工程文件,少了一个都不行的那种,然后有了这个基础就可以去分析标准库工程缺少什么了。
3.2 寄存器版工程创建:
选择创建一个C project
输入工程名字,选择empty project, 再选择arm cross gcc,点击next,再点next,最后的finish按钮先别点。
看到下图这个界面,要选择编译工程的工具链,toolchain name选择下图的,toolchain path如果你刚才安装gcc编译工具链时是默认安装路径的话就是"C:\Program Files (x86)\GNU Tools Arm Embedded\9 2019-q4-major\bin"这个路径,如下图所示,选完就点finish
接下来就是工程文件的准备,去stm32官网下载hal库(为的是一个syscalls.c文件)和标准库,寄存器版本的必要文件有3个:startup_stm32f10x_md.S(启动文件),syscalls.c,stm32_flash.ld(链接脚本文件),先在hal库里找syscalls.c,进入到hal库的下图的目录
由于不同的stm32f1系列的芯片的syscalls.c是不一样的(其实我是看着它的大小不一感觉它们不一样,但后来我用f1的syscalls.c放到f4的工程编译出的程序一样没什么问题,不过这里还是选对应芯片的文件吧,免留后患,和stm32f103c8t6相近的芯片型号是第一个文件夹的芯片工程文件,没错这里只能选相近型号的,怎么看是不是和自己芯片型号是否相近呢,就拿stm32f103c8t6为例,它是一个ram是20K,rom是64K的芯片,接下来我们打开上图的第一个文件夹,打开至下图的目录),然后用记事本打开STM32F103VBIx_FLASH.ld脚本文件
在该文件中对应有该工程文件对应芯片的rom和ram信息,可见这个是和stm32f103c8t6比较相近的,如下图所示
确定了和自己芯片型号相近的工程文件后,就在那个工程文件夹里面找到syscalls.c,这里我以stm32f103c8t6为例子,定位到下图的目录就可以找到这个文件了
右击复制这个文件,然后打开eclipse,右击工程,选择粘贴,这个文件就复制到了你的工程了,如下图。其实细心的你可以发现这个目录中有一个启动文件,再打开第一个文件夹你还可以看到一个STM32F103VBIx_FLASH.ld的脚本链接文件,没错这些都是可以用于创建你的工程文件的,如果你是真的用寄存器开发的话完全可以在这个目录找齐那3个必须文件了,这里考虑到大多数人是标准库开发,所以下边就还会讲一下如何在标准库里找到符合gcc的启动文件和脚本链接文件
现在就转到标准库的文件夹下去找启动文件和脚本链接文件,这里就不截图了,那个路径太长截图没意义
启动文件:STM32F10x_StdPeriph_Lib_V3.5.0\Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x\startup\TrueSTUDIO
在这个路径下选这符合自己芯片的启动文件,百度一下就知道怎么选了,stm32f103c8t6是选startup_stm32f10x_md.s,像刚刚那样复制到eclipse的工程里。
脚本链接文件:STM32F10x_StdPeriph_Lib_V3.5.0\Project\STM32F10x_StdPeriph_Template\TrueSTUDIO\STM3210B-EVAL
这里以stm32f103c8t6为例子选这个STM3210B-EVAL文件夹里的stm32_flash.ld文件复制到eclipse的工程里去,确定自己芯片对应文件夹在找syscalls.c文件时已经说过,这里也是一样的办法。
现在你的工程下应该是下图的样子的
然后新建一个main.c来写main函数和SystemInit函数,看过野火的教程的都知道这个SystemInit函数是干嘛的了,如果不懂不用怕,因为这里只是告诉你一下,内容我会给出来,让你验证一下工程是否已经成功建立,因为这篇文章就是为萌新设计的,新建.c源文件如下图,右击工程然后…
像下图一样选择选项,名字就main.c吧,你写别的名字也行
main.c的内容如下(下边的内容有点多,也是我自己的寄存器开发时用的代码,算是一个分享吧,有兴趣的可以看一下,不要求你看懂,只要求你复制到工程中的main.c文件进行验证工程是否成功配置):
#define u32 unsigned int
#define u16 unsigned short int
#define u8 unsigned char
#define vlt volatile
#include <stdio.h>
#include <stdlib.h>
#define bit(X) (1<<X)
u32 range(u32 i, u32 j)
{
u32 bit_range=0;
for(;i<=j;i++)
{
bit_range |= 1<<i;
}
return (bit_range);
}
void Reg(volatile u32 * p, u32 range, u32 set)
{
u32 date;
date=*p;
date &= ~range;
date |= set;
*p=date;
}
#define APB1 ((u32)0x40000000)
#define APB2 (APB1+0x00010000)
#define AHB (APB1+0x00018000)
#define GPIOA (APB2+0x00000800)
#define GPIOB (APB2+0x00000C00)
#define GPIOC (APB2+0x00001000)
#define GPIOD (APB2+0x00001400)
#define GPIOE (APB2+0x00001800)
#define GPIOF (APB2+0x00001C00)
#define GPIOG (APB2+0x00002000)
struct GPIOX
{
volatile u32 CRL;
volatile u32 CRH;
volatile u32 IDR;
volatile u32 ODR;
volatile u32 BSRR;
volatile u32 BRR;
volatile u32 LCKR;
};
#define PA ((struct GPIOX *)GPIOA)
#define PB ((struct GPIOX *)GPIOB)
#define PC ((struct GPIOX *)GPIOC)
#define PD ((struct GPIOX *)GPIOD)
#define PE ((struct GPIOX *)GPIOE)
#define PF ((struct GPIOX *)GPIOF)
#define PG ((struct GPIOX *)GPIOG)
#define io(X) 1<<X
enum IOM
{
Is = 0 ,
If = 4 ,
Iud = 8 ,
Ih = 12,
O2gp = 2 ,
O2go = 6 ,
O2mp = 10,
O2mo = 14,
O10gp= 1 ,
O10go= 5 ,
O10mp= 9 ,
O10mo= 13,
O50gp= 3 ,
O50go= 7 ,
O50mp= 11,
O50mo= 15
};
void IOs(struct GPIOX * P, u32 io, enum IOM mode) // IOs(PC,io(13),O2gp);
{
int i;
u32 set_CR;
set_CR=P->CRL;
for(i=0;i<=7;i++)
{
if(io&(1<<i))
{
set_CR &= ~(0xF<<(i*4));
set_CR |= mode<<(i*4);
}
}
P->CRL=set_CR;
set_CR=P->CRH;
for(i=0;i<=7;i++)
{
if(io&(1<<(i+8)))
{
set_CR &= ~(0xF<<(i*4));
set_CR |= mode<<(i*4);
}
}
P->CRH=set_CR;
}
struct AFIOX
{
volatile u32 EVCR;
volatile u32 MAPR;
volatile u32 EXTICR1;
volatile u32 EXTICR2;
volatile u32 EXTICR3;
volatile u32 EXTICR4;
};
#define AFIO ((struct AFIOX *)APB2)
#define RCCA (AHB+0x00009000)
struct RCCX
{
volatile u32 CR;
volatile u32 CFGR;
volatile u32 CIR;
volatile u32 APB2RSTR;
volatile u32 APB1RSTR;
volatile u32 AHBENR;
volatile u32 APB2ENR;
volatile u32 APB1ENR;
volatile u32 BDCR;
volatile u32 CSR;
};
#define RCC ((struct RCCX *)RCCA)
#define SDIO bit(10) //AHBENR
#define FSMC bit(8)
#define CRC bit(6)
#define FLITF bit(4)
#define SRAM bit(2)
#define DMA_2 bit(1)
#define DMA_1 bit(0)
#define ADC_3 bit(15) //APB2ENR
#define USART_1 bit(14)
#define TIM8 bit(13)
#define SPI_1 bit(12)
#define TIM1 bit(11)
#define ADC_2 bit(10)
#define ADC_1 bit(9)
#define IOPG bit(8)
#define IOPF bit(7)
#define IOPE bit(6)
#define IOPD bit(5)
#define IOPC bit(4)
#define IOPB bit(3)
#define IOPA bit(2)
#define IOAF bit(0)
#define DAC bit(29) //APB1ENR
#define PWR bit(28)
#define BKP bit(25)
#define USB bit(23)
#define I2C_2 bit(22)
#define I2C_1 bit(21)
#define UART_5 bit(20)
#define UART_4 bit(19)
#define USART_3 bit(18)
#define USART_2 bit(17)
#define SPI_3 bit(15)
#define SPI_2 bit(14)
#define WWDG bit(11)
#define TIM7 bit(5)
#define TIM6 bit(4)
#define TIM5 bit(3)
#define TIM4 bit(2)
#define TIM3 bit(1)
#define TIM2 bit(0)
void AHBEN(struct RCCX * P, u32 choose, u32 m)
{
int i;
u32 set;
set=P->AHBENR;
for(i=0;i<=10;i++)
{
if(choose&(1<<i))
{
set &= ~(1<<i);
set |= m<<i;
}
}
P->AHBENR=set;
}
void APB2EN(struct RCCX * P, u32 choose, u32 m) // APB2EN(RCC, IOPA|IOPC, 1);
{
int i;
u32 set;
set=P->APB2ENR;
for(i=0;i<=15;i++)
{
if(choose&(1<<i))
{
set &= ~(1<<i);
set |= m<<i;
}
}
P->APB2ENR=set;
}
void APB1EN(struct RCCX * P, u32 choose, u32 m)
{
int i;
u32 set;
set=P->APB1ENR;
for(i=0;i<=29;i++)
{
if(choose&(1<<i))
{
set &= ~(1<<i);
set |= m<<i;
}
}
P->APB1ENR=set;
}
#define PAo(X) *((volatile u32 *)(0x42000000+(GPIOA+0x0C-0x40000000)*32+4*X)) // PCo(13)=0;
#define PBo(X) *((volatile u32 *)(0x42000000+(GPIOB+0x0C-0x40000000)*32+4*X))
#define PCo(X) *((volatile u32 *)(0x42000000+(GPIOC+0x0C-0x40000000)*32+4*X))
#define PDo(X) *((volatile u32 *)(0x42000000+(GPIOD+0x0C-0x40000000)*32+4*X))
#define PEo(X) *((volatile u32 *)(0x42000000+(GPIOE+0x0C-0x40000000)*32+4*X))
#define PFo(X) *((volatile u32 *)(0x42000000+(GPIOF+0x0C-0x40000000)*32+4*X))
#define PGo(X) *((volatile u32 *)(0x42000000+(GPIOG+0x0C-0x40000000)*32+4*X))
#define PAi(X) *((volatile u32 *)(0x42000000+(GPIOA+0x08-0x40000000)*32+4*X))
#define PBi(X) *((volatile u32 *)(0x42000000+(GPIOB+0x08-0x40000000)*32+4*X))
#define PCi(X) *((volatile u32 *)(0x42000000+(GPIOC+0x08-0x40000000)*32+4*X))
#define PDi(X) *((volatile u32 *)(0x42000000+(GPIOD+0x08-0x40000000)*32+4*X))
#define PEi(X) *((volatile u32 *)(0x42000000+(GPIOE+0x08-0x40000000)*32+4*X))
#define PFi(X) *((volatile u32 *)(0x42000000+(GPIOF+0x08-0x40000000)*32+4*X))
#define PGi(X) *((volatile u32 *)(0x42000000+(GPIOG+0x08-0x40000000)*32+4*X))
volatile u32 * Bit(volatile u32 * p, u32 X)
{
return ((volatile u32 *)(0x42000000+((u32)p-0x40000000)*32+4*X));
}
#define Bit(p,X) (*Bit(p,X)) // Bit(&PC->ODR,13)=0;
#define Flash (AHB+0x0000A000)
struct FLASHX
{
volatile u32 ACR;
volatile u32 KEYR;
volatile u32 OPTKEYR;
volatile u32 SR;
volatile u32 CR;
volatile u32 AR;
volatile u32 Rsd;
volatile u32 OBR;
volatile u32 WRPR;
};
#define FLASH ((struct FLASHX *)Flash)
#define Exti (APB2+0x400)
struct EXTIX
{
volatile u32 IMR;
volatile u32 EMR;
volatile u32 RTSR;
volatile u32 FTSR;
volatile u32 SWIER;
volatile u32 PR;
};
#define EXTI ((struct EXTIX *)Exti)
#define Scs 0xE000E000
#define Nvic (Scs+0x0100)
#define Scb (Scs+0x0D00)
#define IDr (Scs+0x0FD0)
struct SCSX
{
vlt u32 Rsd0;
vlt u32 ICTR; //0x04
vlt u32 Rsd1[2];
vlt u32 STKCSR; //0x10
vlt u32 STKRDR; //0x14
vlt u32 STKCDR; //0x18
vlt u32 STKADR; //0x1C
};
struct NVICX
{
vlt u32 SETENA[8]; //0x00-0x1C
vlt u32 Rsd0[24];
vlt u32 CLRENA[8]; //0x80-0x9C
vlt u32 Rsd1[24];
vlt u32 SETPEND[8]; //0x100-0x11C
vlt u32 Rsd2[24];
vlt u32 CLRPEND[8]; //0x180-0x19C
vlt u32 Rsd3[24];
vlt u32 ACTIVE[8]; //0x200-0x21C
vlt u32 Rsd4[56];
vlt u8 PRI[240]; //0x300-0x3EF
vlt u32 Rsd5[644];
vlt u32 STIR; //0xE00
};
struct SCBX
{
vlt u32 CPUID; //0x00
vlt u32 ICSR; //0x04
vlt u32 VTOR; //0x08
vlt u32 ATRCR; //0x0C
vlt u32 SYSCR; //0x10
vlt u32 CFCR; //0x14
vlt u8 PRI[12]; //0x18-0x23
vlt u32 SHCSR; //0x24
vlt u8 MFSR; //0x28
vlt u8 BFSR; //0x29
vlt u16 UFSR; //0x2A
vlt u32 HFR; //0x2C
vlt u32 DFSR; //0x30
vlt u32 MMAR; //0x34
vlt u32 BFAR; //0x38
vlt u32 AFAR; //0x3C
vlt u32 Rsd0[20];
vlt u32 MPUTR; //0x90
vlt u32 MPUCR; //0x94
vlt u32 MPURNR0; //0x98
vlt u32 MPURNR1; //0x9C
vlt u32 MPURASR; //0xA0
vlt u32 Rsd1[19];
vlt u32 DHCSR; //0xF0
vlt u32 DCRSR; //0xF4
vlt u32 DCRDR; //0xF8
vlt u32 DEMCR; //0xFC
};
struct IDRX
{
vlt u32 PERIPHID4; //0x00
vlt u32 PERIPHID5; //0x04
vlt u32 PERIPHID6; //0x08
vlt u32 PERIPHID7; //0x0C
vlt u32 PERIPHID0; //0x10
vlt u32 PERIPHID1; //0x14
vlt u32 PERIPHID2; //0x18
vlt u32 PERIPHID3; //0x1C
vlt u32 PCELLID0; //0x20
vlt u32 PCELLID1; //0x24
vlt u32 PCELLID2; //0x28
vlt u32 PCELLID3; //0x2C
};
#define SCS ((struct SCSX *)Scs)
#define NVIC ((struct NVICX *)Nvic)
#define SCB ((struct SCBX *)Scb)
#define IDR ((struct IDRX *)IDr)
#define Usart1 (APB2+0x3800)
#define Usart2 (APB1+0x4400)
#define Usart3 (APB1+0x4800)
#define Uart4 (APB1+0x4C00)
#define Uart5 (APB1+0x5000)
struct USARTX
{
vlt u32 SR;
vlt u32 DR;
vlt u32 BRR;
vlt u32 CR1;
vlt u32 CR2;
vlt u32 CR3;
vlt u32 GTPR;
};
#define USART1 ((struct USARTX *)Usart1)
#define USART2 ((struct USARTX *)Usart2)
#define USART3 ((struct USARTX *)Usart3)
#define UART4 ((struct USARTX *)Uart4)
#define UART5 ((struct USARTX *)Uart5)
void delay(vlt u32 num)
{
while(num--);
}
int main()
{
char * a;
char b;
setbuf(stdout, NULL);
setbuf(stdin, NULL);
APB2EN(RCC, IOPA, 1); //打开usart1的io口对应的时钟
//USART1配置//
IOs(PA, io(9), O50mp);
IOs(PA, io(10), If);
APB2EN(RCC, USART_1, 1);
USART1->DR=0; //要清空一下数据寄存器,不然第一个字符会乱码
Reg(&USART1->BRR, 0, (39<<4)|1); //115200波特率
Reg(&USART1->CR3, 0, range(6, 7));
Reg(&USART1->CR1, 0, bit(13)|bit(3)|bit(2));
a=malloc(8);
*a='9';
printf("\r\n这是一个寄存器版工程\r\n");
printf("123456%c\r\n please input two char: ",*a);
scanf("%c %c",a,&b);
printf("\r\n The char what you input just now are: %c,%c",*a,b);
free(a);
APB2EN(RCC, IOPC, 1); //打开led对应io口的时钟
IOs(PC, io(13), O50gp); //配置对应led的io口
while(1)
{
PCo(13)=~PCo(13); //led闪烁
delay(888888);
}
}
void SystemInit()
{
Bit(&RCC->CR,16)=1;
while(! Bit(&RCC->CR,17));
Bit(&FLASH->ACR,4)=1;
Reg(&FLASH->ACR, bit(0)|bit(1), bit(1));
// FLASH->ACR &= ~(0x03);
// Bit(&FLASH->ACR,1)=1;
Bit(&RCC->CFGR,10)=1; //只对APB1二分频,其他两个默认不分频
Reg(&RCC->CFGR, range(16,21), range(15,16)|range(18,20)); //8*9=72M,ADC时钟为12M
// RCC->CFGR &= ~(0x3F0000);
// RCC->CFGR |= (0x1C0000|0x10000); //8*9=72M
Bit(&RCC->CR,24)=1;
while(Bit(&RCC->CR,25));
Reg(&RCC->CFGR, range(0,1), bit(1));
// RCC->CFGR &= ~(0x3);
// Bit(&RCC->CFGR,1)=1;
while(! Bit(&RCC->CFGR,3));
}
再建一个.c文件叫redifine_printf_scanf.c,这个就是用来放重定义printf和scanf函数的源文件,它的内容如下(不要求看懂,要求你复制到对应的工程文件):
#define TI (*(unsigned int *)0x4227001C) //发送结束标志: TXE
#define RI (*(unsigned int *)0x42270014) //接收标志: RXNE
#define SBUF (*(unsigned int *)0x40013804) //接收发送寄存器,即: USART1->DR
int __io_putchar(int ch) //与printf函数相关的函数
{
TI=0;
SBUF = ch;
while(!TI);
return ch;
}
void Usend(unsigned char ch) //用于回显的函数
{
SBUF = ch;
while (!TI);
}
int __io_getchar(void) //与scanf函数相关的函数
{
int temp = 0;
Gagain:
while (!RI);
temp = SBUF;
RI=0;
if (temp == 0x0d)
{
Usend(0x0a);
Usend(0x0d);
}
else if (temp == 0x08)
{
goto Gagain;
}
else
{
Usend(temp);
}
return (temp);
}
给出上边的两个文件也是为了让大家如果在建立别的芯片的工程时遇到问题,可以参考一下上边的操作,里面有一些注释是有重要信息的,在eclipse里面看代码是很方便舒服的,没必要在这个界面看,接下来要把启动文件的后缀由.s改成大写的.S(右击文件点rename),因为eclipse只识别后缀为大写S的汇编文件。
到现在工程下应该是下图这个样子
那么现在文件准备就绪,下面配置工程参数,右击工程,点击最下边的properties,如下图所示
然后打开到下图的功能块,下图有这个功能区块的简单介绍
有一些东西是默认设置好的了,这里要设置的有:芯片型号选择,脚本链接文件的选择,选择用newlib,选择生成bin(方便看到代码的实际大小以及后面的下载程序工作配置)
芯片型号选择
展开devices(不是展开boards),然后选择对应自己芯片的,如下图
然后切回到 tool settings,选择脚本链接文件,如下两图
选择工程中的链接脚本文件,如下图,然后一直OK就行
选择用newlib
选择生成bin(默认是生成Hex的),最后点apply and close
最后就可以左击一下选定工程,然后点击左上角的锤子进行编译项目了,如下图
如果左上角没有锤子的话只是你没有切换到cdt的开发界面,在右上角有切换的图标,点击一下就可,如下图所示
编译完成,显示0错误,0警告,如下图,那么恭喜你一个寄存器版的工程已经建好了,下边先介绍怎么搭建标准库的再讲怎么把程序下载到芯片和程序的调试,所以这个工程先别删除,留着后边做下载调试测试
3.3 标准库版工程创建:
有了寄存器工程的建立基础,标准库的工程就简单了,首先像建立寄存器版工程一样,创建一个empty工程,我这里命名为example1,这里就不截图了,上边寄存器版的工程已有讲怎么建empty工程,然后进入标准库文件夹去找文件,所需的文件有:
库文件(整个文件夹复制到工程,如下图):STM32F10x_StdPeriph_Lib_V3.5.0\Libraries\STM32F10x_StdPeriph_Driver
内核支持文件(下边分别列出他们的路径):core_cm3.c,core_cm3.h,stm32f10x.h,system_stm32f10x.c,system_stm32f10x.h
core_cm3.c,core_cm3.h(把整个CoreSupport文件夹复制到工程):STM32F10x_StdPeriph_Lib_V3.5.0\Libraries\CMSIS\CM3\CoreSupport
stm32f10x.h,system_stm32f10x.c,system_stm32f10x.h(在下面的路径找到这三个文件,然后复制到工程里的CoreSupport文件夹):
STM32F10x_StdPeriph_Lib_V3.5.0\Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x
用户文件(stm32f10x_conf.h,stm32f10x_it.c,stm32f10x_it.h,把它们复制到工程目录):STM32F10x_StdPeriph_Lib_V3.5.0\Project\STM32F10x_StdPeriph_Template
然后就到寄存器版工程建立时所必需的3个文件了(startup_stm32f10x_md.S(启动文件),syscalls.c,stm32_flash.ld(链接脚本文件)),这里由于寄存器版工程已经建立成功了,我们直接在寄存器版工程目录把这三个文件复制到标准库版的工程,如果你没看寄存器版工程的建立,就可以去里面看看这三个文件是在哪里找到的,要注意的是启动文件注意后缀改成大写的S
再就是redifine_printf_scanf.c,重定义printf和scanf函数文件,与寄存器版工程通用,故直接从寄存器版本工程复制过来
然后建立一个main.c文件,内容如下:
#include <stdlib.h>
#include <stdio.h>
#include "stm32f10x.h"
void LED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_SetBits(GPIOC,GPIO_Pin_13);
}
void usart1_init()
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
USART_InitTypeDef USART_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
USART_InitStructure.USART_BaudRate = 115200;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx|USART_Mode_Tx;
USART_Init(USART1, &USART_InitStructure);
USART_Cmd(USART1, ENABLE);
}
void delay(volatile u32 num)
{
while(num--);
}
int main(void)
{
char * a;
char b;
setbuf(stdout, NULL); //这一行是必须加上程序的,它是标准库的函数,用途自行百度,去掉编译器不会报错,但printf函数没有\n时会出问题
setbuf(stdin, NULL); //这一行最好也加上,它是标准库的函数,用途自行百度,去掉编译器不会报错,与scanf函数有关
LED_Init();
usart1_init();
a=malloc(8);
*a='9';
printf("\r\n这是一个标准库版工程\r\n");
printf("123456%c\r\n please input two char: ",*a);
scanf("%c %c",a,&b);
printf("\r\n The char what you input just now are: %c,%c",*a,b);
free(a);
while(1)
{
GPIO_ResetBits(GPIOC,GPIO_Pin_13);
delay(888888);
GPIO_SetBits(GPIOC,GPIO_Pin_13);
delay(888888);
}
}
这个main.c文件中的东西可能在eclipse里显示出错(如下图),这是正常的,因为还没设置好标准库的路径
到目前为止,你的工程应是下边的样子,看看自己有没有缺文件
确认没有缺文件后就整理一下这些文件,确实看着很乱,在工程中新建3个文件夹,分别为LIB(放关于标准库的文件),USER(放用户文件),DOC(放工程描述文件,这个暂时是空的),整理过后应该是下边这样的
整理完后就先改一改core_cm3.c文件的两个错误,像下图一样展开core_cm3.c,然后找到__STREXB和__STREXH
双击__STREXB,就会定位到该文件的这个函数,如下图
这里要对这两个函数进行修改一下把"=r"改成"=&r",改完后应该为下面的样子,改完记得点保存
uint32_t __STREXB(uint8_t value, uint8_t *addr)
{
uint32_t result=0;
__ASM volatile ("strexb %0, %2, [%1]" : "=&r" (result) : "r" (addr), "r" (value) );
return(result);
}
uint32_t __STREXH(uint16_t value, uint16_t *addr)
{
uint32_t result=0;
__ASM volatile ("strexh %0, %2, [%1]" : "=&r" (result) : "r" (addr), "r" (value) );
return(result);
}
然后再改一下stm32f10x_it.c里的一个错误,其实也不算错误,这个文件在USER文件夹,它包含的第一个头文件为
#include “USER/stm32f10x_it.h”
这个其实没有错,但是等我们设置完路径后那个"USER/"就是多余的了,如果不去掉前面的"USER/"编译会提示
fatal error: USER/stm32f10x_it.h: No such file or directory
就是找不到这个USER/stm32f10x_it.h文件,当然找不到了因为根本没有一个这样一个名字的文件,所以改为
#include “stm32f10x_it.h”
改完后记得点保存,因为eclipse默认是不会编译前自动保存的,如下图
接下来就是工程参数的设置了,这里需要设置的是:芯片型号选择,脚本链接文件的选择,选择用newlib,选择生成bin(方便看到代码的实际大小以及后面的下载程序工作配置),定义Symbol,添加C源文件和头文件的路径。前4项工作我们在建立寄存器版本是已经讲过了,这边我就讲一下后两个
定义Symbol:添加下边的两个定义,第二个根据自己的芯片类型定义
USE_STDPERIPH_DRIVER
STM32F10X_MD
添加定义后应该是下图的样子
添加C源文件和头文件的路径:把刚刚那些库文件用户文件的文件夹路径都添加进来,其实就是告诉编译器在这些路径里面查找C源文件和头文件(寄存器版没有添加是因为所有文件都在工程目录了,故不用添加),如下图进行添加
添加完后应该是下图的样子,注意一下那些路径的顺序
进行完上边的6项设置后,就点apply and close,这边就可以看到没有错误显示了,如下图
如果还有错误显示可能是eclipse刷新不及时,那么就按下图点击Rebuild
如果还有错误那就有可能你疏忽了上边的哪一步骤了,没有问题后我们就点击左上角的那个锤子进行构建,等待构建完成就是0错误,0警告了,那么标准库版的工程就建好了,这里先讲一下这个编译,如果你的工程编译时出错了,改完后记得点保存,然后再clean一下自己的工程,如下两图
clean完工程再点左上角的锤子进行构建就没问题了
有时候我们想一个文件留在工程里但是却不想编译时编译它那就可以先左击选中这个文件,然后再右击它,再点properties,如下图
再进行下图操作
点完apply and close后你会发现这个文件变成灰色了,代表编译时不编译它了,如下图
3.4 程序下载与调试部分:
下边讲解如何把程序下载到芯片上并进行调试,分成三个部分,第一个是J-Link的,第二个是ST-Link的,第三个是CMSIS-DAP的
3.4.1 J-Link的程序下载与调试
3.4.1.1 Jlink的程序下载
首先去segger官网(https://www.segger.com/downloads/jlink/)下载J-Link的驱动,找到下图的地方,按下图操作
在下图的地方可以选择下载那个版本号的驱动程序,这里提一下,不是最新的驱动版本就是最好的,要符合自己的jlink硬件的驱动才是最好的,由于我用的是jlink-v7硬件版本,所以我这边在下边选择版本号时就选了最低版本V5.00版本下载,这个版本对jlink-v7兼容比较好,如果jlink-v7用v6.xx的jlink驱动会时不时就出错,我是实践过才这么说的,其他硬件版本的兼容的驱动就有待你们自己实践去找了
下载解压后就是一个exe安装程序,里边有程序安装路径选择的,然后也没什么特别的了,就是记得那个路径,后边会用到,然后在eclipse的工程里新建一个叫download.jlink的文件(这个文件用来放jlink下载程序时的一些命令的,里面定义了你工程的bin文件的路径),如下两图
这个download.jlink文件的内容如下(注意这个文件最后面要空出一行)
h
loadfile "工程路径\Debug\工程名字.bin" 0x08000000
r
g
exit
上边的download.jlink文件的内容并不是完整的,这边需要你进行修改为符合你自己工程的,就是把(工程路径)替换为自己这个工程的路径,把(工程名字)替换成自己这个工程的名字,下边告诉你在哪找到这两个参数,右击自己的工程,然后点击properties,如下两图
这两个参数找到后就可以在download.jlink文件里进行替换了,以我这里的工程为例子,替换过后内容如下图
然后按下两图操作
按照上图的提示进行设置:
驱动程序里的JLink.exe:如果你是默认路径安装jlink驱动的话那就是:C:\Program Files (x86)\SEGGER\JLink_V500\JLink.exe
选择download.jlink的那个工程:点击Browse Workspace…,然后选对应的工程就可
设置jlink下载命令(要注意一下你对应的芯片类型,我这里以stm32f103c8t6为例就设置成下面的参数,这个型号是有讲究的,要在这个网址(https://www.segger.com/downloads/supported-devices.php)里边找对应型号的芯片,里面的芯片较多要找仔细点,可见下图,stm32f103c8t6对应的是stm32f103c8,所以下边的参数就设置成stm32f103c8)
-device stm32f103c8 -if swd -speed 4000 -commandfile download.jlink
以我的芯片型号为例设置好后就是下图的样子
然后点到Build,这里就是设置运行这个外部工具时是否对工程进行编译,我觉得我一般是编译成功后再点外部工具进行下载程序的,所以我就把那个勾去掉了,如下图,如果你不去掉的话这个勾最好设置一下让它只编译你当前的工程,搜一下那些英文就知道怎么设置了
然后切到common,勾上下图的勾,再点击apply,然后点击close
然后把你的板子连上电脑后,按照下图进行操作
然后出现下图的提示就代表程序下载成功了,那么现在就可以验证一下刚刚的工程程序是否编译正确了
用串口连上开发板的usart1,因为这个程序我是设置usart1使用printf和scanf函数的,波特率设置为115200,打开串口,点一下开发板的RST键,就会提示输入2个字符,然后输入两个字符后敲一个回车然后发送,就会是下图的情况,并且led闪烁起来了(这边设置的是PC13为led的io口),看一下main函数代码你就知道printf函数和scanf函数已经成功执行了
这里提一下如果有多个同一个芯片的工程怎么下载程序吧,你可能会说像上边那样再建立多几个对应的外部工具不就行了,但我想说没必要,你只需要在每个工程中都新建一个download.jlink文件(里面的参数设置成对应工程的),然后再把那个"J-Link下载到STM32F103C8T6"的外部工具的"Working Directory"改成对应工程的然后点击运行,这时就把对应工程的bin文件下载到单片机了,操作如下图描述
刷写成功,可见提示说是寄存器版工程了,如下图
3.4.1.2 Jlink的调试:
接下来就是Jlink的调试了,按下图流程操作进入debug配置
如下图就是新创建的debug,这里我们默认对example1工程(标准库版)进行调试,所以下边就默认就选好了,不用管,倒是上边的debug名字你可以根据自己需要改一下
然后切换到debugger,如下图是介绍
这里进行四项操作:选择jlink驱动里的JLinkGDBServerCL.exe,设置jlink支持对应的芯片型号,进行上图的方框中的设置,选gcc编译工具链的gdb
选择jlink驱动里的JLinkGDBServerCL.exe(默认安装路径的话,这个exe可在下边的路径中找到):
C:\Program Files (x86)\SEGGER\JLink_V500\JLinkGDBServerCL.exe
设置jlink支持对应的芯片型号:这一项在上边的程序下载那部分已经讲过了,在那个网址里找对应自己芯片的型号然后填进去
进行上图的方框中的设置:安照上图设置就OK了
选gcc编译工具链的gdb(这个gcc的gdb的全名是arm-none-eabi-gdb.exe,如果安装gcc时是默认安装路径的话就是下边的路径):
C:\Program Files (x86)\GNU Tools Arm Embedded\9 2019-q4-major\bin\arm-none-eabi-gdb.exe
进行完上边的四步操作后你的debugger界面应该是上边那个图那样子的,看看有没有遗漏,没有问题就继续下边的操作
然后就跳出一个提示问你是否跳转到调试界面,那个选跳转就OK了,然后就到了下图的调试界面,说明调试设置成功,并附上介绍
点击退出调试的按钮,你会发现eclipse没有返回工程开发界面而是停留在了调试界面,时就要看下图的介绍了,由于我们是用C开发所以我们点击C工程开发界面的图标,就可以回到c开发环境了
对于不同的工程也可以用上边的方法去多建立一个debug,但是如果是同型号的芯片又不想建太多的debug,可以在这个debug的配置里面把它的工程换了,照样是可以实现一个debug调试多个同一芯片型号的工程的,如下图进行新两步操作:选定一个需调试工程,然后再点击搜索选定工程的可调试文件(注意要编译成功后的工程才会有可调试文件),当选定了对应工程的可调试文件就可以对选定的工程进行调试了
再点击debug就可以切换到example寄存器版工程的调试界面了,如下图
下边再介绍一下调试的快捷方式,运行的快捷入口和外部工具的快捷方式,介绍如下图,如果你想调试工程却用了运行快捷入口进入了调试时会没法进入调试界面或者报错
3.4.2 ST-Link的程序下载与调试
这里需要下载stlink的驱动和openocd,这里给出这两个软件的百度云链接(链接:https://pan.baidu.com/s/10rWfxdk4XFtxp_FFUzAX8Q
提取码:sder),其实这两个东西都可以百度进行下载,而且openocd是开源的,也一直在更新,我这里给出的stlink驱动是stlink-v2的windows10版本的,安装好stlink驱动,然后再把openocd那个压缩包解压到你喜欢的地方,最好不要放到有中文的目录里,并把这个路径记住,待会要用
3.4.2.1 ST-Link的程序下载
这里有两种办法,一种是用stlink驱动配置,另一种是用openocd配置
3.4.2.1.1 stlink驱动配置的程序下载
stlink驱动配置的程序下载:首先打开外部工具配置,然后新建一个外部工具,不会的话可以看看上边的jlink是怎么新建外部工具的,新建完成后请看下图的描述来大概了解一下接下来的操作
选择ST-LINK_CLI.exe(如果是默认安装stlink驱动的路径的话就是下边的路径):
C:\Program Files (x86)\STMicroelectronics\STM32 ST-LINK Utility\ST-LINK Utility\ST-LINK_CLI.exe
选择工程:直接点上图的位置选择你的工程就好了,我这里就是选example1来作为例子
设置stlink下载参数(参数如下):
-P "工程路径\Debug\工程名字.bin" 0x08000000 -V -Rst
上面的参数中有两个参数是需要根据你自己的工程实际情况替换的,上边讲jlink的时候已经介绍过这两个参数怎么找到了,这里就不重复讲了,进行上边三步操作后应为下图的样子
再进行下边两图的操作,具体意义jlink讲过,不再重复
然后用stlink连上电脑和开发板,点运行,出现下图字样就是下载程序成功了
3.4.2.1.2 stlink用openocd配置下载程序
首先打开外部工具配置,然后新建一个外部工具,不会的话可以看看上边的jlink是怎么新建外部工具的,新建完成后请看下图的描述来大概了解一下接下来的操作
选择openocd.exe(这个exe在那个解压出的openocd文件夹里,下边是以我的路径为例子,你的openocd.exe的路径根据你解压的压缩包的位置而定):
D:\Eclipse\OpenOCD-20200524-0.10.0\bin\openocd.exe
选择工程:直接点上图的位置选择你的工程就好了,我这里就是选example1来作为例子
设置openocd参数(参数如下):
-f "调试器配置文件路径" -f "目标芯片配置文件路径" -c "init;halt;reset halt;flash write_image erase Debug/工程名字.bin 0x08000000;reset;shutdown;"
上边有三个参数需要根据你的实际情况进行替换,一个是"调试器配置文件路径",再一个是"目标芯片配置文件路径",还有一个是"工程名字",工程名字jlink讲过怎么找到,这里就不再讲了,不懂就往上翻一翻jlink的下载程序部分,这里先讲一下openocd的命令再告诉你剩下的两个参数怎么找到,"-f 配置文件"这个命令是告诉openocd加载这个配置文件,"-c 命令"这个命令是告诉openocd对目标芯片执行什么命令,在上边的两个"-f 配置文件"命令(-f “调试器配置文件路径” -f “目标芯片配置文件路径”)之后,openocd就可以通过调试器把电脑和目标芯片进行连接通信了,最后一个"-c 命令"(-c “init;halt;reset halt;flash write_image erase Debug/工程名字.bin 0x08000000;reset;shutdown;”)就是openocd通过调试器把目标芯片和电脑连接后的操作,懂点英文的都知道是进行了什么操作了,命令介绍完毕,“调试器配置文件路径"需要你到解压出的openocd文件里找,这里我用的是stlink-v2调试器,所以我选择stlink-v2.cfg文件,在我的电脑上它的路径是:D:\Eclipse\OpenOCD-20200524-0.10.0\share\openocd\scripts\interface\stlink-v2.cfg,所以我这里的"调试器配置文件路径"参数替换成"D:\Eclipse\OpenOCD-20200524-0.10.0\share\openocd\scripts\interface\stlink-v2.cfg”,我的目标芯片(stm32f103c8t6)的配置文件为stm32f1x.cfg,在我的电脑上它的路径是:D:\Eclipse\OpenOCD-20200524-0.10.0\share\openocd\scripts\target\stm32f1x.cfg,所以我这里的"目标芯片配置文件路径"参数替换成"D:\Eclipse\OpenOCD-20200524-0.10.0\share\openocd\scripts\target\stm32f1x.cfg",把参数替换完后就是下图的样子
再进行下边两图的操作,具体意义jlink讲过,不再重复
点击运行,出现下图的字样代表下载程序成功了
3.4.2.2 stlink调试程序(这里搭配openocd调试):
看下图操作
下边是将要进行的操作和创建成功debug后的界面介绍,与jlink配置调试部分有些类似
下图介绍了要进行的操作,其中选择openocd.exe上边下载程序时讲过了,这里讲一下设置openocd参数,这个参数只比上边的程序下载部分少了"-c 命令"这个参数,也就是下图的设置openocd参数为:
-f "调试器配置文件路径" -f "目标芯片配置文件路径"
里面的"调试器配置文件路径"和"目标芯片配置文件路径"是要你替换掉的,上边下载程序时已经讲过怎么得到这两个参数,这里不再重复
进行完上图的操作后应该是下图这个样子的
进行下图操作,然后点debug
点完debug等待工程编译完成就可以将入调试界面了,如下图,这也代表stlink调试程序设置完成
3.4.3 cmsis-dap的程序下载和调试(基于openocd,所以你要先下载openocd,我在上边stlink下载和调试程序教程的开头已经给出链接,你也可以百度下载,我这里的目标芯片为STM32F429IGT6,因为我的cmsis-dap调试器就是搭配这个芯片的):
3.4.3.1 配置cmsis-dap的程序下载:
这个和stlink使用openocd下载程序有点类似,首先打开外部工具配置,新建一个外部工具,不懂的可以看看上边的jlink配置程序下载,那里讲过这里就不重复了,新建成功后就是下图的样子,下图给出了将要进行的操作
选择openocd.exe:在stlink搭配openocd下载程序时已经讲过,不懂可以看看上边,这里不再重复
选择工程:选择自己工程就OK
设置openocd的下载程序参数(参数如下):
-f "调试器配置文件路径" -f "目标芯片配置文件路径" -c "init;halt;reset halt;flash write_image erase Debug/工程名字.bin 0x08000000;reset;shutdown;"
上边需要你替换一下"调试器配置文件路径","目标芯片配置文件路径"和"工程名字"这个三个参数,其中"工程名字"参数在jlink配置时讲过这里不再讲,"调试器配置文件路径"和"目标芯片配置文件路径"这两个参数在stlink搭配openocd下载程序时讲过,不同的是调试器配置文件要选cmsis-dap.cfg,目标芯片配置文件选择你对应的芯片的cfg文件就可以,那么设置好上图的内容后应该是下图这个样子
再进行下边两图的操作,具体意义jlink讲过,不再重复
点击运行,有下图的字样就是程序下载成功了
3.4.3.2 配置cmsis-dap的程序调试:
看下图操作
下边是将要进行的操作和创建成功debug后的界面介绍,与jlink配置调试部分有些类似
下图介绍了要进行的操作,其中选择openocd.exe上边下载程序时讲过了,这里讲一下设置openocd参数,这个参数只比上边的程序下载部分少了"-c 命令"这个参数,也就是下图的设置openocd参数为:
-f "调试器配置文件路径" -f "目标芯片配置文件路径"
里面的"调试器配置文件路径"和"目标芯片配置文件路径"是要你替换掉的,上边下载程序时已经讲过怎么得到这两个参数,这里不再重复
进行完上图的操作后应该是下图这个样子的
进行下图操作,然后点debug
然后出现下图就是配置debug成功了
3.4.4 这里给出上边三个例子工程的链接给大家下载参考一下(链接:https://pan.baidu.com/s/1zPOP8UYADP6TNwmqN2pX-A 提取码:estp),把工程导入eclipse就可查看了
4 Eclipse cdt 的自动补全代码:
到目前为止32单片机的开发环境就已经建好了,但是你会发现eclipse竟然没有自动补全代码这个功能,那么这个时候就要自己动手改一下eclipse的插件了,见下面的操作
打开eclipse的插件市场
搜索:eclipse pde,见下图操作,加载的过程时间可能比较长
勾选下图功能,然后就是一步步地确认安装
安装完之后,进行下边操作
在Plug-ins窗口中找到下图的那个插件,右键单击,选择import as -> source project,导入之后在你的 workspace就可以看到这个插件工程。
找到
/org.eclipse.cdt.ui/src/org.eclipse.cdt.internal.ui.text.contentassist/ContentAssistProcessor.java
修改public void setCompletionProposalAutoActivationCharacters(char[] activationSet)
public void setCompletionProposalAutoActivationCharacters(char[] activationSet) {
// fCompletionAutoActivationCharacters = activationSet;
String test = ".ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
char[] triggers = test.toCharArray();
fCompletionAutoActivationCharacters = triggers;
}
如下图
找到
/org.eclipse.cdt.ui/src/org.eclipse.cdt.internal.ui.text.contentassist/CContentAssistProcessor.java
修改protected boolean verifyAutoActivation(ITextViewer viewer, int offset)
protected boolean verifyAutoActivation(ITextViewer viewer, int offset) {
IDocument doc = viewer.getDocument();
if (doc == null) {
return false;
}
if (offset <= 0) {
return false;
}
try {
char activationChar = doc.getChar(--offset);
switch (activationChar) {
case ':':
return offset > 0 && doc.getChar(--offset) == ':';
case '>':
return offset > 0 && doc.getChar(--offset) == '-';
case '.':
// Avoid completion of float literals
CHeuristicScanner scanner = new CHeuristicScanner(doc);
int token = scanner.previousToken(--offset, Math.max(0, offset - 200));
// The scanner reports numbers as identifiers
if (token == Symbols.TokenIDENT
&& !Character.isJavaIdentifierStart(doc.getChar(scanner.getPosition() + 1))) {
// Not a valid identifier
return false;
}
return true;
default:
return activationChar >= 97 && activationChar <= 122?true:activationChar >= 65 && activationChar <= 90;
}
} catch (BadLocationException e) {
}
return false;
}
如下图
修改完后点保存,然后导出工程,在工程上右键->Export,选择JAR file
然后等待java的编译完成就可以在你刚刚设置的目录里找到那个jar文件,然后打开eclipse的安装目录的plugins文件夹,找到org.eclipse.cdt.ui_版本号.jar,如我的这个插件的版本号为6.7.0.202003021149,所以我找到的这个jar文件全名就是:org.eclipse.cdt.ui_6.7.0.202003021149.jar,如下图
然后把这个jar文件的名字复制下来,把刚刚导出的jar文件改成复制的名字,然后再把改完名字的这个导出的jar文件覆盖原来的文件,如果你不放心的话可以在覆盖前先备份一下之前的jar文件,然后重启eclipse,就可以使用自动代码补全了,如下图
5 开发51单片机:
编译器选择sdcc,这里eclipse也是要借助插件,但是这个插件年代比较久远,以至于需要借助cygwin的帮助才能运行起来,首先说明一点使用sdcc编译出的程序比keil的大一点而且效率没有keil高,还有一点就是在keil适用的软件延时函数到sdcc后就会变得延迟时间更长了
5.1 cygwin下载与安装:
这里推荐一个博主的文章,他讲的cygwin安装教程比较好(https://blog.csdn.net/u010356768/article/details/90756742)美中不足的是这个博主在教你安装完cygwin后没有告诉你要添加环境变量,这里我们需把cygwin安装目录下的bin文件夹添加到系统环境变量中的path中,这个在一安装eclipse时有提到,下边就给一个配置好了环境变量的图给你参考一下,这个由于我是把cygwin安装在了D盘根目录,所以是下边的这个路径,你根据你自己安装cygwin的路径来改变
5.2 sdcc下载:
sdcc官网(http://sdcc.sourceforge.net/)
下图告诉你在哪点下载sdcc,虽然不大但是下载速度挺慢的,下载完后是一个exe安装程序,直接打开它使用默认的设置安装就可以了
5.3 eclipse sdcc插件下载:
(https://sourceforge.net/projects/eclipse-sdcc/)
下载完插件后就把这个压缩包接压缩到eclipse安装目录的dropins文件夹里,如下图
然后打开cygwin安装目录的bin文件夹,找里边的sh.exe文件并复制它,如下图,然后把它粘贴到刚刚那个插件的这个路径:…\eclipse\dropins\net.sourceforge.eclipsesdcc-1.0.0-win32.x86\plugins\net.sourceforge.eclipsesdcc_1.0.0(如下边第二张图)
5.4 工程的创建与配置
然后重启一下eclipse,再点击新建一个c project,如下图
创建好工程后就配置工程参数,如下图
改成下图的构建工具
转到下图可以进行设置工程的包含路径
设置生成hex文件,如下图
然后点apply and close,到现在就把工程设置好了,现在你可以把C源文件和头文件复制到这个工程里面了
5.5 SDCC与keil的语法对比
sdcc的某些语法和keil是不同的,下边列出语法的不同之处的对比
keil sdcc
_nop_(); __asm
nop
__endasm;
sbit P00 = P0^0; __sbit __at 0x80 P00;
sfr P0 = 0x80; __sfr __at 0x80 P0;
bit __bit volatile
interrupt __interrupt
code __code
语法是不同的,使用上也是有不同的,下边介绍一下吧
//定义一个io口为led时,如定义P00为led
keil sdcc
sbit led = P0^0; __sbit __at 0x80 led;
#define led P00
//sdcc定义一个中断函数,需要在main函数上边对中断函数进行声明,否则你的中断函数就是无效的,如下
void uart(void) __interrupt 4; //对中断函数进行声明
void main()
{
while(1)
{
//在下边写入自己的main函数内容
}
}
void uart() __interrupt 4
{
//在下边写入自己的中断函数内容
}
然后下边给出我自己修改成sdcc语法的stc12c5a60s2的头文件内容
#ifndef __my_STC12C5A60S2_H_
#define __my_STC12C5A60S2_H_
/////////////////////////////////////////////////
//--------------------------------------------------------------------------------
//新一代 1T 8051系列 单片机内核特殊功能寄存器 C51 Core SFRs
// 7 6 5 4 3 2 1 0 Reset Value
__sfr __at 0xE0 ACC; //Accumulator 0000,0000
__sfr __at 0xF0 B; //B Register 0000,0000
__sfr __at 0xD0 PSW; //Program Status Word CY AC F0 RS1 RS0 OV F1 P 0000,0000
//-----------------------------------
__sbit __at 0xD7 CY;
__sbit __at 0xD6 AC;
__sbit __at 0xD5 F0;
__sbit __at 0xD4 RS1;
__sbit __at 0xD3 RS0;
__sbit __at 0xD2 OV;
__sbit __at 0xD0 P;
//-----------------------------------
__sfr __at 0x81 SP; //Stack Pointer 0000,0111
__sfr __at 0x82 DPL; //Data Pointer Low Byte 0000,0000
__sfr __at 0x83 DPH; //Data Pointer High Byte 0000,0000
//--------------------------------------------------------------------------------
//新一代 1T 8051系列 单片机系统管理特殊功能寄存器
// 7 6 5 4 3 2 1 0 Reset Value
__sfr __at 0x87 PCON; //Power Control SMOD SMOD0 LVDF POF GF1 GF0 PD IDL 0001,0000
// 7 6 5 4 3 2 1 0 Reset Value
__sfr __at 0x8E AUXR; //Auxiliary Register T0x12 T1x12 UART_M0x6 BRTR S2SMOD BRTx12 EXTRAM S1BRS 0000,0000
//-----------------------------------
__sfr __at 0xA2 AUXR1; //Auxiliary Register 1 - PCA_P4 SPI_P4 S2_P4 GF2 ADRJ - DPS 0000,0000
//-----------------------------------
__sfr __at 0x8F WAKE_CLKO; //附加的 SFR WAK1_CLKO
//-----------------------------------
__sfr __at 0x97 CLK_DIV; //Clock Divder - - - - - CLKS2 CLKS1 CLKS0 xxxx,x000
//-----------------------------------
__sfr __at 0xA1 BUS_SPEED; //Stretch register - - ALES1 ALES0 - RWS2 RWS1 RWS0 xx10,x011
//--------------------------------------------------------------------------------
//新一代 1T 8051系列 单片机中断特殊功能寄存器
//有的中断控制、中断标志位散布在其它特殊功能寄存器中,这些位在位地址中定义
//其中有的位无位寻址能力,请参阅 新一代 1T 8051系列 单片机中文指南
// 7 6 5 4 3 2 1 0 Reset Value
__sfr __at 0xA8 IE; //中断控制寄存器 EA ELVD EADC ES ET1 EX1 ET0 EX0 0x00,0000
//-----------------------
__sbit __at 0xAF EA;
__sbit __at 0xAE ELVD; //低压监测中断允许位
__sbit __at 0xAD EADC; //ADC 中断允许位
__sbit __at 0xAC ES;
__sbit __at 0xAB ET1;
__sbit __at 0xAA EX1;
__sbit __at 0xA9 ET0;
__sbit __at 0xA8 EX0;
//-----------------------
__sfr __at 0xAF IE2; //Auxiliary Interrupt - - - - - - ESPI ES2 0000,0000B
//-----------------------
// 7 6 5 4 3 2 1 0 Reset Value
__sfr __at 0xB8 IP; //中断优先级低位 PPCA PLVD PADC PS PT1 PX1 PT0 PX0 0000,0000
//--------
__sbit __at 0xBF PPCA; //PCA 模块中断优先级
__sbit __at 0xBE PLVD; //低压监测中断优先级
__sbit __at 0xBD PADC; //ADC 中断优先级
__sbit __at 0xBC PS;
__sbit __at 0xBB PT1;
__sbit __at 0xBA PX1;
__sbit __at 0xB9 PT0;
__sbit __at 0xB8 PX0;
//-----------------------
// 7 6 5 4 3 2 1 0 Reset Value
__sfr __at 0xB7 IPH; //中断优先级高位 PPCAH PLVDH PADCH PSH PT1H PX1H PT0H PX0H 0000,0000
__sfr __at 0xB5 IP2; // - - - - - - PSPI PS2 xxxx,xx00
__sfr __at 0xB6 IPH2; // - - - - - - PSPIH PS2H xxxx,xx00
//-----------------------
//新一代 1T 8051系列 单片机I/O 口特殊功能寄存器
// 7 6 5 4 3 2 1 0 Reset Value
__sfr __at 0x80 P0; //8 bitPort0 P0.7 P0.6 P0.5 P0.4 P0.3 P0.2 P0.1 P0.0 1111,1111
__sbit __at 0x80 P00;
__sbit __at 0x81 P01;
__sbit __at 0x82 P02;
__sbit __at 0x83 P03;
__sbit __at 0x84 P04;
__sbit __at 0x85 P05;
__sbit __at 0x86 P06;
__sbit __at 0x87 P07;
__sfr __at 0x94 P0M0; // 0000,0000
__sfr __at 0x93 P0M1; // 0000,0000
__sfr __at 0x90 P1; //8 bitPort1 P1.7 P1.6 P1.5 P1.4 P1.3 P1.2 P1.1 P1.0 1111,1111
__sbit __at 0x90 P10;
__sbit __at 0x91 P11;
__sbit __at 0x92 P12;
__sbit __at 0x93 P13;
__sbit __at 0x94 P14;
__sbit __at 0x95 P15;
__sbit __at 0x96 P16;
__sbit __at 0x97 P17;
__sfr __at 0x92 P1M0; // 0000,0000
__sfr __at 0x91 P1M1; // 0000,0000
__sfr __at 0x9D P1ASF; //P1 analog special function
__sfr __at 0xA0 P2; //8 bitPort2 P2.7 P2.6 P2.5 P2.4 P2.3 P2.2 P2.1 P2.0 1111,1111
__sbit __at 0xA0 P20;
__sbit __at 0xA1 P21;
__sbit __at 0xA2 P22;
__sbit __at 0xA3 P23;
__sbit __at 0xA4 P24;
__sbit __at 0xA5 P25;
__sbit __at 0xA6 P26;
__sbit __at 0xA7 P27;
__sfr __at 0x96 P2M0; // 0000,0000
__sfr __at 0x95 P2M1; // 0000,0000
__sfr __at 0xB0 P3; //8 bitPort3 P3.7 P3.6 P3.5 P3.4 P3.3 P3.2 P3.1 P3.0 1111,1111
__sbit __at 0xB0 P30;
__sbit __at 0xB1 P31;
__sbit __at 0xB2 P32;
__sbit __at 0xB3 P33;
__sbit __at 0xB4 P34;
__sbit __at 0xB5 P35;
__sbit __at 0xB6 P36;
__sbit __at 0xB7 P37;
__sfr __at 0xB2 P3M0; // 0000,0000
__sfr __at 0xB1 P3M1; // 0000,0000
__sfr __at 0xC0 P4; //8 bitPort4 P4.7 P4.6 P4.5 P4.4 P4.3 P4.2 P4.1 P4.0 1111,1111
__sbit __at 0xC0 P40;
__sbit __at 0xC1 P41;
__sbit __at 0xC2 P42;
__sbit __at 0xC3 P43;
__sbit __at 0xC4 P44;
__sbit __at 0xC5 P45;
__sbit __at 0xC6 P46;
__sbit __at 0xC7 P47;
__sfr __at 0xB4 P4M0; // 0000,0000
__sfr __at 0xB3 P4M1; // 0000,0000
// 7 6 5 4 3 2 1 0 Reset Value
__sfr __at 0xBB P4SW; //Port-4 switch - LVD_P4.6 ALE_P4.5 NA_P4.4 - - - - x000,xxxx
__sfr __at 0xC8 P5; //8 bitPort5 - - - - P5.3 P5.2 P5.1 P5.0 xxxx,1111
__sbit __at 0xC8 P50;
__sbit __at 0xC9 P51;
__sbit __at 0xCA P52;
__sbit __at 0xCB P53;
__sfr __at 0xCA P5M0; // 0000,0000
__sfr __at 0xC9 P5M1; // 0000,0000
//--------------------------------------------------------------------------------
//新一代 1T 8051系列 单片机定时器特殊功能寄存器
// 7 6 5 4 3 2 1 0 Reset Value
__sfr __at 0x88 TCON; //T0/T1 Control TF1 TR1 TF0 TR0 IE1 IT1 IE0 IT0 0000,0000
//-----------------------------------
__sbit __at 0x8F TF1;
__sbit __at 0x8E TR1;
__sbit __at 0x8D TF0;
__sbit __at 0x8C TR0;
__sbit __at 0x8B IE1;
__sbit __at 0x8A IT1;
__sbit __at 0x89 IE0;
__sbit __at 0x88 IT0;
//-----------------------------------
__sfr __at 0x89 TMOD; //T0/T1 Modes GATE1 C/T1 M1_1 M1_0 GATE0 C/T0 M0_1 M0_0 0000,0000
__sfr __at 0x8A TL0; //T0 Low Byte 0000,0000
__sfr __at 0x8C TH0; //T0 High Byte 0000,0000
__sfr __at 0x8B TL1; //T1 Low Byte 0000,0000
__sfr __at 0x8D TH1; //T1 High Byte 0000,0000
//--------------------------------------------------------------------------------
//新一代 1T 8051系列 单片机串行口特殊功能寄存器
// 7 6 5 4 3 2 1 0 Reset Value
__sfr __at 0x98 SCON; //Serial Control SM0/FE SM1 SM2 REN TB8 RB8 TI RI 0000,0000
//-----------------------------------
__sbit __at 0x9F SM0; //SM0/FE
__sbit __at 0x9E SM1;
__sbit __at 0x9D SM2;
__sbit __at 0x9C REN;
__sbit __at 0x9B TB8;
__sbit __at 0x9A RB8;
__sbit __at 0x99 TI;
__sbit __at 0x98 RI;
//-----------------------------------
__sfr __at 0x99 SBUF; //Serial Data Buffer xxxx,xxxx
__sfr __at 0xB9 SADEN; //Slave Address Mask 0000,0000
__sfr __at 0xA9 SADDR; //Slave Address 0000,0000
//-----------------------------------
// 7 6 5 4 3 2 1 0 Reset Value
__sfr __at 0x9A S2CON; //S2 Control S2SM0 S2SM1 S2SM2 S2REN S2TB8 S2RB8 S2TI S2RI 00000000B
__sfr __at 0x9B S2BUF; //S2 Serial Buffer xxxx,xxxx
__sfr __at 0x9C BRT; //S2 Baud-Rate Timer 0000,0000
//--------------------------------------------------------------------------------
//新一代 1T 8051系列 单片机看门狗定时器特殊功能寄存器
__sfr __at 0xC1 WDT_CONTR; //Watch-Dog-Timer Control register
// 7 6 5 4 3 2 1 0 Reset Value
// WDT_FLAG - EN_WDT CLR_WDT IDLE_WDT PS2 PS1 PS0 xx00,0000
//-----------------------
//--------------------------------------------------------------------------------
//新一代 1T 8051系列 单片机PCA/PWM 特殊功能寄存器
// 7 6 5 4 3 2 1 0 Reset Value
__sfr __at 0xD8 CCON; //PCA 控制寄存器。 CF CR - - - - CCF1 CCF0 00xx,xx00
//-----------------------
__sbit __at 0xDF CF; //PCA计数器溢出标志,由硬件或软件置位,必须由软件清0。
__sbit __at 0xDE CR; //1:允许 PCA 计数器计数, 必须由软件清0。
//-
//-
__sbit __at 0xD9 CCF1; //PCA 模块1 中断标志, 由硬件置位, 必须由软件清0。
__sbit __at 0xD8 CCF0; //PCA 模块0 中断标志, 由硬件置位, 必须由软件清0。
//-----------------------
__sfr __at 0xD9 CMOD; //PCA 工作模式寄存器。 CIDL - - - CPS2 CPS1 CPS0 ECF 0xxx,x000
//-----------------------
__sfr __at 0xE9 CL; //PCA 计数器低位 0000,0000
__sfr __at 0xF9 CH; //PCA 计数器高位 0000,0000
//-----------------------
// 7 6 5 4 3 2 1 0 Reset Value
__sfr __at 0xDA CCAPM0; //PCA 模块0 PWM 寄存器 - ECOM0 CAPP0 CAPN0 MAT0 TOG0 PWM0 ECCF0 x000,0000
__sfr __at 0xDB CCAPM1; //PCA 模块1 PWM 寄存器 - ECOM1 CAPP1 CAPN1 MAT1 TOG1 PWM1 ECCF1 x000,0000
//ECOMn = 1:允许比较功能。
//CAPPn = 1:允许上升沿触发捕捉功能。
//CAPNn = 1:允许下降沿触发捕捉功能。
//MATn = 1:当匹配情况发生时, 允许 CCON 中的 CCFn 置位。
//TOGn = 1:当匹配情况发生时, CEXn 将翻转。
//PWMn = 1:将 CEXn 设置为 PWM 输出。
//ECCFn = 1:允许 CCON 中的 CCFn 触发中断。
//ECOMn CAPPn CAPNn MATn TOGn PWMn ECCFn
// 0 0 0 0 0 0 0 0x00 未启用任何功能。
// x 1 0 0 0 0 x 0x21 16位CEXn上升沿触发捕捉功能。
// x 0 1 0 0 0 x 0x11 16位CEXn下降沿触发捕捉功能。
// x 1 1 0 0 0 x 0x31 16位CEXn边沿(上、下沿)触发捕捉功能。
// 1 0 0 1 0 0 x 0x49 16位软件定时器。
// 1 0 0 1 1 0 x 0x4d 16位高速脉冲输出。
// 1 0 0 0 0 1 0 0x42 8位 PWM。
//ECOMn CAPPn CAPNn MATn TOGn PWMn ECCFn
// 0 0 0 0 0 0 0 0x00 无此操作
// 1 0 0 0 0 1 0 0x42 普通8位PWM, 无中断
// 1 1 0 0 0 1 1 0x63 PWM输出由低变高可产生中断
// 1 0 1 0 0 1 1 0x53 PWM输出由高变低可产生中断
// 1 1 1 0 0 1 1 0x73 PWM输出由低变高或由高变低都可产生中断
//-----------------------
__sfr __at 0xEA CCAP0L; //PCA 模块 0 的捕捉/比较寄存器低 8 位。 0000,0000
__sfr __at 0xFA CCAP0H; //PCA 模块 0 的捕捉/比较寄存器高 8 位。 0000,0000
__sfr __at 0xEB CCAP1L; //PCA 模块 1 的捕捉/比较寄存器低 8 位。 0000,0000
__sfr __at 0xFB CCAP1H; //PCA 模块 1 的捕捉/比较寄存器高 8 位。 0000,0000
//-----------------------
// 7 6 5 4 3 2 1 0 Reset Value
__sfr __at 0xF2 PCA_PWM0; //PCA 模块0 PWM 寄存器。 - - - - - - EPC0H EPC0L xxxx,xx00
__sfr __at 0xF3 PCA_PWM1; //PCA 模块1 PWM 寄存器。 - - - - - - EPC1H EPC1L xxxx,xx00
//PCA_PWMn: 7 6 5 4 3 2 1 0
// - - - - - - EPCnH EPCnL
//B7-B2: 保留
//B1(EPCnH): 在 PWM 模式下,与 CCAPnH 组成 9 位数。
//B0(EPCnL): 在 PWM 模式下,与 CCAPnL 组成 9 位数。
//--------------------------------------------------------------------------------
//新一代 1T 8051系列 单片机 ADC 特殊功能寄存器
// 7 6 5 4 3 2 1 0 Reset Value
__sfr __at 0xBC ADC_CONTR; //A/D 转换控制寄存器 ADC_POWER SPEED1 SPEED0 ADC_FLAG ADC_START CHS2 CHS1 CHS0 0000,0000
__sfr __at 0xBD ADC_RES; //A/D 转换结果高8位 ADCV.9 ADCV.8 ADCV.7 ADCV.6 ADCV.5 ADCV.4 ADCV.3 ADCV.2 0000,0000
__sfr __at 0xBE ADC_RESL; //A/D 转换结果低2位 ADCV.1 ADCV.0 0000,0000
//--------------------------------------------------------------------------------
//新一代 1T 8051系列 单片机 SPI 特殊功能寄存器
// 7 6 5 4 3 2 1 0 Reset Value
__sfr __at 0xCE SPCTL; //SPI Control Register SSIG SPEN DORD MSTR CPOL CPHA SPR1 SPR0 0000,0100
__sfr __at 0xCD SPSTAT; //SPI Status Register SPIF WCOL - - - - - - 00xx,xxxx
__sfr __at 0xCF SPDAT; //SPI Data Register 0000,0000
//--------------------------------------------------------------------------------
//新一代 1T 8051系列 单片机 IAP/ISP 特殊功能寄存器
__sfr __at 0xC2 IAP_DATA;
__sfr __at 0xC3 IAP_ADDRH;
__sfr __at 0xC4 IAP_ADDRL;
// 7 6 5 4 3 2 1 0 Reset Value
__sfr __at 0xC5 IAP_CMD; //IAP Mode Table 0 - - - - - MS1 MS0 0xxx,xx00
__sfr __at 0xC6 IAP_TRIG;
__sfr __at 0xC7 IAP_CONTR; //IAP Control Register IAPEN SWBS SWRST CFAIL - WT2 WT1 WT0 0000,x000
//--------------------------------------------------------------------------------
/////////////////////////////////////////////////
#endif
这里给出网上搜的一些sdcc其他51芯片的头文件,有一些我试了试还是可以编译成功的(链接:https://pan.baidu.com/s/1tKupLM7YOuXAtOoDg5yvAA
提取码:dxy8),最好先用记事本打开头文件然后再把全部内容复制到你在工程里新建的头文件里边,不然你可能会看到那些文件里的中文全部显示成乱码了,因为大部分文件是用UTF-8编码的。
5.6 Eclipse对sdcc特殊语法不识别
根据上边的语法写完代码并编译(点击左上角的锤子),显示0错误0警告但是,你发现工程里的那些sdcc的特殊语法会报错,这个是没办法的,因为eclipse的cdt不识别这些特殊的语法,但是sdcc编译器是识别的,所以编译会成功,那么,下边就告诉大家如何掩盖这些错误吧,注意这里的掩盖也会导致eclipse减少相应的语法实时检测,如下两图设置
设置完后你会发现实时检测的报错减少不少了,就剩下
中断函数
和
__asm
汇编代码
__endasm;
这两个语法的警告了,这个影响还是比较小的
当编译成功后你会发现在Release文件夹里已经生成了hex文件了
5.7 开发8位单片机的外加资料
如果你还想知道sdcc开发8位单片机的详细细节可以阅读一下下边的两篇文章,我大部分资料也是在这两篇文章参考的:
https://wenku.baidu.com/view/f0e53e62a88271fe910ef12d2af90242a895abab.html
http://www.elecfans.com/emb/app/2009042352989.html
如果你想对比一下sdcc编译出的程序和keil编译出的程序的大小有什么差别,这里就要把hex转换成bin文件对比,因为bin文件才是真正的程序的大小
6 开发C语言:
前提需要你下载并安装cygwin,上边讲51单片机开发时介绍过了
新建一个工程,工程类型选择Empty Project,编译链选择Cygwin GCC
右击新建好的工程并点击Properties
然后点击如图所示的Tool Chain Editor
Current Builder里选择CDT Internal Builder
现在你便可以在项目里创建C源文件进行开发C控制台程序了(注意:这里创建C源文件最好用英文命名,不然后面的调试会出现问题,在eclipse开发最好就用英文命名源文件了),需要注意的是使用这个编译器编译C语言和Microsoft Visual Studio不同,目前我发现的是如果想正常使用printf函数,要在main函数开头加上一句:
setbuf(stdout, NULL);
如下图所示:
C语言控制台程序的编译也是点左上角的锤子,然后编译成功后的运行就要右击工程>>Run As>>Local C/C++ Application 如下图
调试也是一样的,你可以看到上图的Run As下面有一个Debug As,Debug As就是调试,但是你点Debug As>>Local C/C++ Application 会出现下图的错误,那么这个只是提示没有找到调试文件,所以先复制下图中蓝色的那段字体(注意如果你的工程文件在E盘下的话,那么你复制的应该是/cygdrive/e/,而不是/cygdrive/d/,由于我的工程文件在D盘所以我是D,下边进行映射时我就映射到D盘的了,如果你的工程文件在E盘就映射到E盘就好)
然后打开windows>>preference>>c/c++>>debug>>source lookup path,再点击Add,选择Path Mapping,点OK,如下图
然后会弹出下图窗口,可以把名字改成(Cygwin调试),再点击Add
将刚刚复制的东西(/cygdrive/d/)映射为D:\ (这个只是演示,实际盘符看你自己的工程在那个盘符)如下图
然后在再进行调试就可以成功了,但是调试printf和scanf函数时会出现下图错误,提示:stopped,reason=“end-stepping-range”,frame={addr=“0x00000001004010cc”,func=“main”,args=[{name=“argc”,value=“1”},{name=“argv”,value=“0xffffcc30”}],file="…c",fullname="…c",line=“26”},thread-id=“1”,stopped-threads=“all”,有一个办法是在printf函数输出末尾加 \n ,这个确实可以但是却改变了程序的真实意图,而且它这个scanf还好像没法接收我键盘敲过去的数据,下边给出一个彻底解决此问题的办法,请继续往下看。
问题出在程序调试时调用了eclipse的默认控制台,就是上图输出错误的那个窗口,这是eclipse(windows版本)的一个老bug了,一直不修复,估计难度太大了,不过上帝关了这扇门,肯定留了后门给你,于是我Google了一下eclipse社区,找到了办法:Run>>Debug Configurations… 如下图
在C/C++ Application展开项中选择对应你要调试的那个工程配置(一般是“工程名.exe”),我这边要配置的工程名是“C”,所以我选"C.exe"项
然后点击Debugger,并勾上下边的"Use external console for inferior(open a new console window for input/output)"选项,如下图
然后点击Apply,再点击Debug进行调试,这时调试时就会弹出window的dos窗口,如下图,没错这个调试原理就像用vs2010是调试C程序是一样的
然后这时单步调试到printf函数就不会有问题了,并且在这个dos窗口显示了输出的结果(要你自己手动点出这个窗口查看)
单步执行scanf函数,调试器就要求你在dos窗口进行输入信息了,如下图,这里建议不要用小键盘输入数据,尽量用大键盘,连回车也最好用大键盘的
输入数据回车后就可以继续调试下去了,执行到main函数的return函数可能会有下图的情况,这个没什么影响,不用管直接停止调试退出就OK了。
7 Eclipse功能拓展:
到目前eclipse的四个开发环境就搭建好了,下边提一下eclipse的一些功能,只是告诉你eclipse有什么功能,具体怎么设置请大家去百度或者自己探索,这里只是提一下:
1.多核编译
2.通过下载eclipse的插件设置成黑色主题(不装插件的eclipse也有默认的黑色主题)
3.设置编译前自动保存
4.设置多少时间自动保存代码
5.改编辑器的字体
6.改工作空间的编码格式
7.自定义代码的不同标识符的颜色
8.汉化eclipse
9.更新eclipse
等等
经过一波骚操作后就是下图的样子了
8 最后感谢下边的文章提供的帮助:
http://www.openedv.com/forum.php?mod=viewthread&tid=92845&highlight=eclipse(为eclipse开发32提供帮助)
https://wenku.baidu.com/view/f0e53e62a88271fe910ef12d2af90242a895abab.html(为eclipse开发51单片机提供帮助)
https://blog.csdn.net/na2wo4/article/details/105631236?utm_medium=distribute.pc_relevant_download.none-task-blog-BlogCommendFromBaidu-2.nonecase&depth_1-utm_source=distribute.pc_relevant_download.none-task-blog-BlogCommendFromBaidu-2.nonecas(为eclipse的cdt提供代码自动补全)
感谢百度和eclipse社区还有eclipse mcu插件作者