M16C族单片机为原三菱电机生产的16位CISC微控制器。
主要特点为:
低电压,低功耗,抗干扰性强
具备大容量FLASH ROM, SRAM
丰富的外设,如定时器,AD,DA,CAN控制器等
所有这些特性,使M16C广泛应用汽车,电动车,工业设备及家电产品上。
下面我们讲讲如何在M16C平台下编程。
1. 使用HEW新建一个工程。
打开HEW,选择Create a new project workspace,点OK。
选择CPU family,这里我们选择M16C选项。
工具链Tool chain我们默认选择Renesas M16C Standard。
好了,接下来我们要输入一个工程名字,在workspace name里输入m16c_test。
接下来,注意,也是最重要的一步,在左边的project types下面,我们选择C source startup Application这个选项,该选项的含义是你将建立一个C语言开始的工程。当然,如果选择第一个Application,则为汇编语言开始的工程。
考虑到大多数朋友对M16C的汇编不是很熟悉,我们这里以C语言工程为参考。
点确定后,继续选择工具链版本5.43.00,CPU Series我选择为M16C/60, CPU Group我选择为6N4,然后点next,继续点next使用默认选项,最后选择targets为M16C E8a SYSTEM,这是是你的CPU要用到的仿真器,我们一般使用瑞萨产的小型ON Chip debugger仿真器E8a.
点next,最后点Finish。OK,我们的一个C语言工程已经建好了。
2. 工程源文件分析
我们发现我们建的m16c_test工程里面有一些源代码文件。下面我们对这些文件进行分析。
(注意:建立工程时,选择不同的选项可能会产生不同的源代码文件,不过这不影响我们的使用)
m16c_test.c
源代码:
/*****************************/
void main(void)
{
}
该文件是main()函数。你的所有应用函数都会在main()里调用
resetprg.c
源代码:
/*****************************/
#include "sfr6n4.h"
#include "typedefine.h"
#include "resetprg.h"
extern _UINT _stack_top,_istack_top;
//DEF_BANKSELECT;
DEF_SBREGISTER;
#pragma entry start
void start(void);
extern void initsct(void);
extern void _init(void);
void exit(void);
void main(void);
#pragma section program interrupt
void start(void)
{
_isp_ = &_istack_top; // set interrupt stack pointer
prcr = 0x02; // change protect mode register
pm0 = 0x00; // set processor mode register
prcr = 0x00; // change protect mode register
_flg_ = __F_value__; // set flag register
#if __STACKSIZE__!=0
_sp_ = &_stack_top; // set user stack pointer
#endif
_sb_ = 0x400; // 400H fixation (Do not change)
// set variable vector's address
_asm(" ldc #((topof vector)>>16)&0FFFFh,INTBH");
_asm(" ldc #(topof vector)&0FFFFh,INTBL");
initsct(); // initlalize each sections
#if __HEAPSIZE__ != 0
heap_init(); // initialize heap
#endif
#if __STANDARD_IO__ != 0
_init(); // initialize standard I/O
#endif
_fb_ = 0; // initialize FB registe for debugger
main(); // call main routine
exit(); // call exit
}
void exit(void)
{
while(1); // infinite loop
}
该文件为上电复位处理
start()为CPU上电复位后执行的第一个函数。我们可以在这里设置中断栈指针寄存器,处理器模式等。最终它将调用main()函数。
intprg.c
源代码:
/*****************************/
#include "sfr6n4.h"
#include "cstartdef.h"
// BRK (software int 0)
#pragma interrupt _brk(vect=0)
void _brk(void){}
// can0/1wakeup (software int 1)
#pragma interrupt _can0(vect=1)
void _can0(void){}
// can0 receive (software int 2)
#pragma interrupt _can0_receive(vect=2)
void _can0_receive(void){}
// can0 trance (software int 3)
#pragma interrupt _can0_trance(vect=3)
void _can0_trance(void){}
// ____
// INT3 (software int 4)
#pragma interrupt _int3(vect=4)
void _int3(void){}
// TIMER B5 (software int 5)
#pragma interrupt _timer_b5(vect=5)
void _timer_b5(void){}
// TIMER B4,UART1 bus collision (software int 6)
#pragma interrupt _timer_b4(vect=6)
void _timer_b4(void){}
// TIMER B3,UART0 bus collision (software int 7)
#pragma interrupt _timer_b3(vect=7)
void _timer_b3(void){}
// ____
// can1 receive/INT5 (software int 8)
#pragma interrupt _can1_receive(vect=8)
void _can1_receive(void){}
// SI/O3/can1 trance (software int 9)
#pragma interrupt _can1_trance(vect=9)
void _can1_trance(void){}
// UART2 Bus Collision (software int 10)
#pragma interrupt _u2_bus_collision(vect=10)
void _u2_bus_collision(void){}
// DMA0 (software int 11)
#pragma interrupt _dma0(vect=11)
void _dma0(void){}
// DMA1 (software int 12)
#pragma interrupt _dma1(vect=12)
void _dma1(void){}
// can0/1 error (software int 13)
#pragma interrupt _can0_error(vect=13)
void _can0_error(void){}
// A-D/input key (software int 14)
#pragma interrupt _ad_converter(vect=14)
void _ad_converter(void){}
// uart2 trance/NACK2 (software int 15)
#pragma interrupt _uart2_trance(vect=15)
void _uart2_trance(void){}
// uart2 receive/ACK2 (software int 16)
#pragma interrupt _uart2_receive(vect=16)
void _uart2_receive(void){}
#if defined (__STANDARD_IO__) && (defined(__FOUSB__) || defined(__E8__))
// uart0 can't be used
#else
// uart0 trance/NACK0 (software int 17)
#pragma interrupt _uart0_trance(vect=17)
void _uart0_trance(void){}
#endif
// uart0 receive/ACK0 (software int 18)
#pragma interrupt _uart0_receive(vect=18)
void _uart0_receive(void){}
#if defined(__STANDARD_IO__) || defined(__FOUSB__) || defined(__E8__)
// uart1 can't be used
#else
// uart1 trance/NACK1 (software int 19)
#pragma interrupt _uart1_trance(vect=19)
void _uart1_trance(void){}
#endif
// uart1 receive/ACK1 (software int 20)
#pragma interrupt _uart1_receive(vect=20)
void _uart1_receive(void){}
// TIMER A0 (software int 21)
#pragma interrupt _timer_a0(vect=21)
void _timer_a0(void){}
// TIMER A1 (software int 22)
#pragma interrupt _timer_a1(vect=22)
void _timer_a1(void){}
// TIMER A2 (software int 23)
#pragma interrupt _timer_a2(vect=23)
void _timer_a2(void){}
// TIMER A3 (software int 24)
#pragma interrupt _timer_a3(vect=24)
void _timer_a3(void){}
// TIMER A4 (software int 25)
#pragma interrupt _timer_a4(vect=25)
void _timer_a4(void){}
// timer b0 (software int 26)
#pragma interrupt _timer_b0(vect=26)
void _timer_b0(void){}
// timer b1 (software int 27)
#pragma interrupt _timer_b1(vect=27)
void _timer_b1(void){}
// timer b2 (software int 28)
#pragma interrupt _timer_b2(vect=28)
void _timer_b2(void){}
// ____
// int0 (software int 29)
#pragma interrupt _int0(vect=29)
void _int0(void){}
// ____
// int1 (software int 30)
#pragma interrupt _int1(vect=30)
void _int1(void){}
// ____
// int2 (software int 31)
#pragma interrupt _int2(vect=31)
void _int2(void){}
// software int 32 for user or MR30
// software int 33 for user or MR30
// software int 34 for user or MR30
// software int 35 for user or MR30
// software int 36 for user or MR30
// software int 37 for user or MR30
// software int 38 for user or MR30
// software int 39 for user or MR30
// software int 40 for user or MR30
// software int 41 for user or MR30
// software int 42 for user or MR30
// software int 43 for user or MR30
// software int 44 for user or MR30
// software int 45 for user or MR30
// software int 46 for user or MR30
// software int 47 for user or MR30
// software int 48 for user
// software int 49 for user
// software int 50 for user
// software int 51 for user
// software int 52 for user
// software int 53 for user
// software int 54 for user
// software int 55 for user
// software int 56 for user
// software int 57 for user
// software int 58 for user
// software int 59 for user
// software int 60 for user
// software int 61 for user
// software int 62 for user
// software int 63 for user
该文件为中断处理子程序。
我们以串口0接收中断为例
// uart0 receive/ACK0 (software int 18)
#pragma interrupt _uart0_receive(vect=18)
void _uart0_receive(void){}
如上,
#pragma interrupt _uart0_receive(vect=18)
#pragma为预处理指令,该语句表示M16C的编译器将_uart0_receive()函数指定为一个中断子函数,向量号为18(可以对照CPU的硬件手册查看串口0接收中断的向量号)
initsct.c
源代码:
/*****************************/
#include "initsct.h"
void initsct(void);
void initsct(void)
{
sclear("bss_SE","data","align");
sclear("bss_SO","data","noalign");
sclear("bss_NE","data","align");
sclear("bss_NO","data","noalign");
sclear_f("bss_FE","data","align");
sclear_f("bss_FO","data","noalign");
// add new sections
// bss_clear("new section name");
scopy("data_SE","data","align");
scopy("data_SO","data","noalign");
scopy("data_NE","data","align");
scopy("data_NO","data","noalign");
scopy_f("data_FE","data","align");
scopy_f("data_FO","data","noalign");
}
该文件为bss,data段的初始化。
其中bss为未初始化数据,data为初始化了的数据
调用initsct()函数时,CPU会将bss段清零,将ROM里的初始化数据复制到data段里。
heap.c
源代码:
/*****************************/
#include "typedefine.h"
#include "cstartdef.h"
#if __HEAPSIZE__ != 0
#pragma SECTION bss heap
_UBYTE heap_area[__HEAPSIZE__];
#endif
该文件为堆的定义。malloc()等函数将会从heap_area[__HEAPSIZE__]数组里申请空间。
当然,你可以定义堆的大小。
fvector.c
源代码:
/*****************************/
#pragma sectaddress fvector,ROMDATA 0xfffdc
#pragma interrupt/v _dummy_int //udi
#pragma interrupt/v _dummy_int //over_flow
#pragma interrupt/v _dummy_int //brki
#pragma interrupt/v _dummy_int //address_match
#pragma interrupt/v _dummy_int //single_step
#pragma interrupt/v _dummy_int //wdt
#pragma interrupt/v _dummy_int //dbc
#pragma interrupt/v _dummy_int //nmi
#pragma interrupt/v start
_asm(" .id ""\"#FFFFFFFFFFFFFF\"");
#pragma interrupt _dummy_int()
void _dummy_int(void){}
该文件为fixed vector table的定义,关于fixed vector向量,可以查看CPU的硬件手册。一般不用更改该文件
**********************************************
好了,我们介绍完了.c文件,下面来介绍.h头文件
sfr6n4.h为M16C/6N4的寄存器定义
typedefine.h为数据结构定义
resetprg.h为复位函数的一些定义
initsct.h为initsct.c的宏定义,主要实现bss清0,data的拷贝。
cstartdef.h为堆和栈的大小定义等。
到这里,我们基本上知道了M16C的工程结构。接下来我们可以根据项目的需求来编程和调试了。
下面简单介绍如何使用E8a调试程序。
将E8A连接上目标板后,HEW工程里面会多了一些选项。
我们可以使用E8A来设置断点(F9),单步(F11,F10),运行程序(F5),复位运行(SHIFT + F5)等。
当然,我们还可以观察CPU的寄存器,FLASH,RAM内容等。
我们还可以使用E8A下载程序。在debug里面有个下载选项,直接选择我们要下载的文件即可。
HEW的功能是很强大的,它支持uITRON等实时操作系统(RTOS)的调试,实现多任务,任务堆栈,信号量,消息机制的在线调试等。不过这个操作系统是收费的,需要向瑞萨购买。
如果你的项目需要用到RTOS,可以使用免费的uCOS等RTOS。
用户377235 2014-11-18 13:46