合泰单片机ht46x65v220使用手册
- 格式:pdf
- 大小:2.58 MB
- 文档页数:50
#include "HT46R47-H.h"//---------------def-----------------------//pa#define _pac0 _13_0#define _pac1 _13_1#define _pac2 _13_2#define _pac3 _13_3#define _pac4 _13_4#define _pac5 _13_5#define _pac6 _13_6#define _pac7 _13_7//pb#define _pbc0 _15_0#define _pbc1 _15_1#define _pbc2 _15_2#define _pbc3 _15_3//pd#define _pdc0 _19_0#define CN_DOWN _pa1#define JM _pa4#define LED_GREEN _pa5#define LED_RED _pa6#define FAN _pa7#define PWM_IO _pd0#define C_SAMP 0x00#define BT_SAMP 0x01#define V_SAMP 0x02#define TIM_PRE 7200 //pre 2H-7200#define TIM_NOML 43920 //CC/CV 12.2H=13H#define OVER_VOLTAGE 0x0c5 //43.57V#define LOW_VOLTAGE 0x068 //24V 0x06b//#define OVER_CURRENT 0x0062 //3.9A 10.5A #define PRE_CHARGER 0x088 //30V#define FULL_DOWN_V 0x0b5 //40V#define FULL_CURRENT 0x05f //0.2A#define N20C_NTC 0x0ec //-20度#define _0C_NTC 0x0d7 //0度#define _45C_NTC 0x089 //45度0x07e//---------------var-----------------------unsigned int adcvalue;unsigned int I_by;unsigned char chargermode;unsigned char T_Mode; //T mode unsigned int ChargingTimeValue; //bit StartTimeFlg;bit ChargingT_OverFlg;unsigned char Tcount;unsigned char SecondCnt;bit UnLoad;bit Start_5S;bit Flg_5S;unsigned char Cnt5s; //5 seconds//---------------ex fuction----------------extern unsigned int ADCStart(unsigned char chanl);//delay 1ms Fsys=4Mhz 实测1msvoid Delay1ms(void){unsigned int va;for(va=0;va<60;va++){;}}//delay N msvoid DelayNms(unsigned int ms){unsigned int vb;for(vb=0;vb<ms;vb++){Delay1ms();}}//----------------------------------------------// 上电自校准电压IV// 自校电压是否在空载范围内void s1_VI(void)while(1){adcvalue = ADCStart(V_SAMP); //voltageif(((adcvalue<0x01ff)||(adcvalue==0x01ff))&&((adcvalue>0x0000)||(adcvalue==0x0000))) {break;}}}//------------------------------------------------// 校正OP电流否正常,条件打开0.05A校正电流// 实测I-V OP放大电压,0x0074 4.2A=0X0141 【0X0141-0X0074=D205,// 4200/205=20.5mA/位ADvoid s1_VI1(void){while(1){adcvalue = ADCStart(C_SAMP); //currentif(((adcvalue<0x01ff)||(adcvalue==0x01ff))&&((adcvalue>0x0000)||(adcvalue==0x0000))) {I_by = adcvalue;break;}}}//system initialvoid SYS_Inital(void){//IOport --------------CN_DOWN = 0;JM = 0;FAN = 0;PWM_IO = 0;LED_GREEN = 0;LED_RED = 1;_pb3 = 0;_pac1 = 0;_pac4 = 0;_pac7 = 0;_pdc0 = 0;_pac5 = 0;_pac6 = 0;_pbc0 = 1;_pbc1 = 1;_pbc2 = 1;_pbc3 = 0;//var ----------------------chargermode = 0x01;Tcount = 0;SecondCnt = 0;//Timer -------------------_tmrc = 0x87; //timer mode Ftimer=Fsys/128 Fsys=4M Ttimer=32us _tmr = (256-250); //32*250=8ms//PWM ---------------------_pwm = 0xfc; //set pwm duty cycle//voltage current just self-----s1_VI();DelayNms(1000);s1_VI1();}//---------------------相关保护void ToPretect(void){//---------------短路保护//---------------低压保护/*adcvalue = ADCStart(V_SAMP); //voltageif(adcvalue<=LOW_VOLTAGE) //Low voltage{adcvalue = ADCStart(C_SAMP); //currentif(adcvalue>20){PWM_IO = 0;JM = 0;chargermode = 0x05; //errorreturn;}}*///---------------过压保护if(adcvalue>=OVER_VOLTAGE) //over voltage {PWM_IO = 0;JM = 0;chargermode = 0x05; //errorreturn;}//---------------过流保护/*adcvalue = ADCStart(C_SAMP); //currentif(adcvalue>=OVER_CURRENT) //over current {PWM_IO = 0;JM = 0;chargermode = 0x05; //errorreturn;}*/}//------------------main-----------void main(){SYS_Inital();_intc=0x05; // EMI ETI enable _ton = 1; //start timerwhile(1){switch(chargermode){case 0x01://startT_Mode = chargermode;ChargingTimeValue = 0;StartTimeFlg = 0;ChargingT_OverFlg = 0;FAN = 0;LED_GREEN = 0;LED_RED = 1;DelayNms(1000);adcvalue = ADCStart(V_SAMP); //voltageif((adcvalue>=OVER_VOLTAGE)) //&&(adcvalue>=LOW_VOLTAGE)//over or low voltage{JM = 0;chargermode = 0x05; //errorbreak;}else{//adcvalue = ADCStart(BT_SAMP); //B temp//if(adcvalue<=N20C_NTC)//if(adcvalue>=LOW_VOLTAGE)//{PWM_IO = 0;JM = 1;DelayNms(1000);adcvalue = ADCStart(C_SAMP); //Currentif(adcvalue>=0x50){//UnLoad = 0;//Start_5S = 0;//Cnt5s = 0;//Flg_5S = 0;//adcvalue = ADCStart(V_SAMP); //voltage//if(adcvalue<=PRE_CHARGER) //24<V<30V-pre//{PWM_IO = 0;chargermode = 0x02; //prebreak;//}//else //V>30V-nor//{// PWM_IO = 1;// chargermode = 0x03; //normal// break;//}}//}}break;case 0x02://PRE_CHARGERPWM_IO = 0;JM = 1;FAN = 0;LED_GREEN = 1;LED_RED = 1;//----------------------------------------- //over timeif(T_Mode!=chargermode){T_Mode = chargermode;ChargingTimeValue = TIM_PRE;StartTimeFlg = 1;ChargingT_OverFlg = 0;}if(ChargingT_OverFlg==1){PWM_IO = 0;JM = 0;chargermode = 0x05; //errorbreak;}//----------低压,过压,过流,短路ToPretect();//----------BMS over tempadcvalue = ADCStart(BT_SAMP); //B tempif(((adcvalue>0xd7)||(adcvalue==0xd7))||((adcvalue<0x7f)||(adcvalue==0x7f))) {PWM_IO = 0;JM = 0;chargermode = 0x05; //errorbreak;}//----------pre to Normaladcvalue = ADCStart(V_SAMP); //voltageif(adcvalue>PRE_CHARGER) //>30V{PWM_IO = 1;chargermode = 0x03; //normal}//------------------------------battery removeadcvalue = ADCStart(BT_SAMP); //battery NTCif(adcvalue>=N20C_NTC) //no ntc{PWM_IO = 0;JM = 0;chargermode = 0x05; //standbybreak;}//---------------adcvalue = ADCStart(V_SAMP); //voltageif(adcvalue<=0x16) //5V{adcvalue = ADCStart(C_SAMP); //currentif(adcvalue>20){JM = 0;PWM_IO = 0;chargermode = 0x05; //errorbreak;}}break;case 0x03://CC+CVPWM_IO = 1;JM = 1;FAN = 1;LED_GREEN = 1;LED_RED = 1;//---------------------timerif(T_Mode!=chargermode){T_Mode = chargermode;ChargingTimeValue = TIM_NOML;StartTimeFlg = 1;ChargingT_OverFlg = 0;}if(ChargingT_OverFlg==1){PWM_IO = 0;chargermode = 0x05; //errorbreak;}//----------低压,过压,过流,短路ToPretect();//-----------------------------normal to FULLadcvalue = ADCStart(V_SAMP); //voltageif(adcvalue>=FULL_DOWN_V) //>40V{adcvalue = ADCStart(C_SAMP); //currentif(adcvalue<=(FULL_CURRENT)) //get FULL{chargermode = 0x04; //fullbreak;}}//----------BMS over tempadcvalue = ADCStart(BT_SAMP); //B temp//0度-0xc2 45度-0x6bif(((adcvalue>0xdb)||(adcvalue==0xdb))||((adcvalue<0x82)||(adcvalue==0x82))) {PWM_IO = 0;JM = 0;chargermode = 0x05; //errorbreak;}//------------------normal to preadcvalue = ADCStart(V_SAMP); //voltageif(adcvalue<(PRE_CHARGER-10)) //PRE{chargermode = 0x02; //prebreak;}//------------------------------battery removeadcvalue = ADCStart(BT_SAMP); //battery NTCif(adcvalue>=N20C_NTC) //no ntc{PWM_IO = 0;JM = 0;chargermode = 0x05; //standby}//---------------adcvalue = ADCStart(V_SAMP); //voltageif(adcvalue<=0x16) //5V{adcvalue = ADCStart(C_SAMP); //currentif(adcvalue>20){JM = 0;PWM_IO = 0;chargermode = 0x05; //errorbreak;}}break;case 0x04://FULL_DOWNT_Mode = chargermode;ChargingTimeValue = 0; //StartTimeFlg = 0;ChargingT_OverFlg = 0;PWM_IO = 0;JM = 0;FAN = 0;LED_GREEN = 1;LED_RED = 0;DelayNms(1000);adcvalue = ADCStart(V_SAMP); //voltageif(adcvalue>OVER_VOLTAGE) //{PWM_IO = 0;JM = 0;chargermode = 0x05; //errorbreak;}else{if(adcvalue<(LOW_VOLTAGE-20)){PWM_IO = 0;JM = 0;chargermode = 0x01; //standbybreak;}}break;case 0x05://errorT_Mode = chargermode;ChargingTimeValue = 0; //StartTimeFlg = 0;ChargingT_OverFlg = 0;PWM_IO = 0;JM = 0;FAN = 0;LED_GREEN = 0;LED_RED = 1;DelayNms(1000);LED_GREEN = 0;LED_RED = 0;DelayNms(1000);break;default:break;}}}。
HT47R20A-1定时/计数器(Timer/Event counter)使用介绍文件编码:HA0031s本文主要介绍HT47R20A-1定时/计数器(Timer/Event counter)的使用及注意事项。
介绍HT47R20A-1有一个16位向上计数的定时/计数器,由TMRAH、TMRAL和TMRBH、TMRBL 组成。
其中TMRAH、TMRAL用来计数;TMRBH、TMRBL是加载寄存器,用来存放定时/计数器的初值。
定时/计数器赋初值时要先写入低字节,再写入高字节,即先写入TMRAL、TMRBL,再写入TMRAH、TMRBH;定时/计数器的时钟来源可以是系统时钟、指令时钟(系统时钟/4)、RTC超TMRC为定时/计数器的控制寄存器,用来定义定时/计数器的运行模式、计数允许/禁止以及触发方式,如下表所示:名称位功能—0~2 未定义,读取时为“0”TE 3定义定时/计数器TMR作用沿(0=上升沿作用,1=下降沿作用)TON 4允许/禁止定时器计数(0=禁止,1=允许)TM0 TM1 TM2 567定义操作方式(TM2,TM1,TM0)000=定时器模式(系统时钟)001=定时器模式(系统时钟/4)010=定时器模式(RTC输出)011=A/D计数模式(由ADCR寄存器决定RC振荡)100=计数器模式(外部时钟)101=脉冲宽度测量模式(系统时钟/4)110=未定义111=未定义TMRC寄存器TM0、TM1和TM2用来定义计数模式。
其中定时器模式用来计数内部时钟,其时钟来源为内部时钟;计数器模式用来计数外部事件,其时钟来源为外部TMR引脚的输入;A/D计数模式是用来计数外部A/D输入(关于A/D转换的使用在此不做详细介绍);脉冲宽度测量模式能够对外部引脚TMR的高电平或低电平的持续时间进行计数,计数的时钟来源为指令时钟。
在定时器模式、A/D计数模式或计数器模式下,一旦定时/计数器开始计数即从定时/计数器的现有值(TMRAH和TMRAL)开始计数至FFFFH。
HT46R53A/HT46R54A A/D 型八位OTP 单片机盛群知识产权政策专利权盛群半导体公司在全球各地区已核准和申请中之专利权至少有160件以上,享有绝对之合法权益。
与盛群公司MCU 或其它产品有关的专利权并未被同意授权使用,任何经由不当手段侵害盛群公司专利权之公司、组织或个人,盛群将采取一切可能的法律行动,遏止侵权者不当的侵权行为,并追讨盛群公司因侵权行为所受之损失、或侵权者所得之不法利益。
商标商标权权盛群之名称和标识、Holtek 标识、HT-IDE 、HT-ICE 、Marvel Speech 、 Music Micro 、 Adlib Micro 、 Magic V oice 、 Green Dialer 、 PagerPro 、 Q-V oice 、 Turbo V oice 、 EasyV oice 和 HandyWriter 都是盛群半导体公司在台湾地区和其它国家的注册商标。
著作权Copyright © 2006 by HOLTEK SEMICONDUCTOR INC.规格书中所出现的信息在出版当时相信是正确的,然而盛群对于规格内容的使用不负责任。
文中提到的应用其目的仅仅是用来做说明,盛群不保证或不表示这些应用没有更深入的修改就能适用,也不推荐它的产品使用在会由于故障或其它原因可能会对人身造成危害的地方。
盛群产品不授权使用于救生、维生器件或系统中做为关键器件。
盛群拥有不事先通知而修改产品的权利,对于最新的信息,请参考我们的网址; HT46R53A/HT46R54A技术相关信息· 工具信息· FAQs· 应用范例− HA0003S HT48 & HT46 MCU 与HT93LC46 EEPROM 的通信− HA0004S HT48 & HT46 MCU UART 的软件实现方法− HA0084S HT46R52 之应用-镍氢电池充电器展示板特性• 低功耗的全静态CMOS设计• 工作电压:• f SYS =4MHz:2.2V~5.5V• f SYS =8MHz:3.3V~5.5V• 程序存储器:2K×15 OTP(HT46R53A)4K×15 OTP(HT46R54A)• 数据存储器:192×8 RAM(HT46R53A)280×8 RAM(HT46R54A)• A/D转换器:12bits×8通道具有外部的A/D转换器的参考电压输入引脚• 有22个双向输入/输出口• 1个与输入/输出口共用引脚的外部中断输入• 8位可编程定时/计数器,具有溢出中断和7级预分频器• 内置晶体和RC振荡电路• 6层硬件堆栈• 看门狗定时器• 低电压复位功能• HALT和唤醒功能可降低功耗• 在VDD=5V,系统频率为8MHz时,指令周期为0.5µs• 1通道8位的PWM输出,与输入/输出口共用引脚• PFD功能• 位操作指令• 查表指令• 63条指令• 指令执行时间为1或2个指令周期• 28-pinSKDIP/SOP封装概述HT46R53A/ HT46R54A是8位高性能精简指令集单片机,专门为需要A/D转换的产品而设计,例如传感器信号输入。
合泰(HT)入门攻略同V100版本相比,多出了如下红色内容目录一、网址链接 (2)1. 芯片选型 (2)2. 工具主页 (2)3. 工具的使用视频 (3)二、HT基本常识 (4)1. Flash/OTP (4)2. 编译器 (4)3. 软件仿真 (4)4. 资料更新 (4)三、HT价格 (5)1. 芯片价格 (5)2. 仿真器价格 (5)3. 烧录器价格 (6)四、HT培训 (7)1. 可以建议购买如下书籍 (7)2. 仿真器购买M1001D+D1003C (7)3. HT官方网站上有应用范例 (7)4. 如果想有人手把手教 (7)五、使用手册 (8)一、网址链接官网1.芯片选型⏹选型系统/ecatalog_mvc_trunk/parametricSearchController.do?compNo=H&groupNo=01⏹简易选型PDF文档/pdf/guide.pdf2.工具主页⏹上位机软体下载/China/tech/tool/MainPage1.htm⏹仿真器/烧录器硬件/China/tech/tool/MainPage1.htm⏹工具搭配组合查询/China/tech/tool/MainPage2.aspx?L=CN○1○2○3⏹IC烧录引脚需知如果不使用HT的专用e-Socket转接座,可考虑使用如下ICP方式:/english/literature/Holtek_MCU_In-Circuit_Programming_Guidelines.pdf3.工具的使用视频/HoltekC500二、HT基本常识1.Flash/OTPFlash:可重复擦写,一般名称带有F字母HT46FXX\HT66FXX系列带AD,HT48FXX\HT68FXX系列不带ADHT46FXX\HT48FXX为较早期Flash,仿真器使用HT-ICEHT66FXX\HT68FXX为近期开发的Flash功能更强,仿真器使用e-ICE/e-Link烧录档后缀为.MTP(Multi Time Program,重复烧录)OTP:不可擦写,一般名称带有R字母即:芯片ROM中的0可以写为1,但1不能再写为0HT46R06X系列带AD,HT48R06X系列不带AD烧录档后缀为.OTP(One Time Program,只烧录1次)2.编译器HT可同时支持“C语言和汇编”编程。
HT46R22单片机在电磁炉功率控制中的应用摘要:介绍了电磁炉的基本工作原理,并提出了一种采用HT46R22单片机实现电磁炉功率稳定输出的功率控制方法,最后简单介绍了该方法的软硬件设计过程。
关键词:电磁炉;HT46R22;功率控制引言近年来,随着环保和节能意识的逐步提高,一种新兴的"绿色的厨具"--电磁炉正在家庭中普及。
它改变了传统的明火烹调方式,利用电磁感应原理,使电流通过内置的线圈时产生磁场,磁场内的磁力线感应到铁制器皿,产生无数高速运动的小涡流,涡流产生的巨大循环能量转换为有效热能,使锅具自行高速加热,最终直接加热食物。
电磁炉的热效率达到90%以上,同时它无烟无灰,无污染,不升高室温,不产生一氧化碳等有害物质,安全环保。
电磁炉还采用了微电脑控制,能够随意控制温度。
正是由于上述种种优点,电磁炉在发达国家的家庭普及率已经达到80%以上。
为了提高电热转换率,家用电磁炉一般采用的是高频电磁炉,须将工频电整流成直流电后再逆变成20kHz以上的高频振荡电流,在高频下,稳定功率输出和实时检测就成了设计的难点和关键所在。
采用Holtek公司产的A/D型单片机HT46R22可以方便地实现定温控制、实时检测、报警检测和功率控制,本文着重介绍功率控制的实现。
1 功率控制设计原理1.1 电磁炉的工作原理电磁炉的工作原理如图1所示,由主电路和控制电路构成。
主电路中220V交流电经整流滤波后加在由电容C1及C2和电感L1与IGBT管S组成的电压谐振变换器上。
变换器主要起两个作用,一是将工频转换为20~40kHz的高频交流电,二是将电能转换为磁能。
高频交流电加在励磁线圈上,通过电磁感应,直接作用于锅具底部,产生涡流,使锅具迅速加热。
控制电路采用单片机HT46R22作为主控制芯片,它能实现许多必要的检测和保护,同时由它产生控制所需的PWM信号,控制电磁炉的输出功率。
1.2 电磁炉的功率控制原理功率控制,就是当工频交流电稳定的情况下,电磁炉能按设定的功率稳定地输出,以使电磁炉能稳定地工作。
合泰单⽚机基础教程第⼀章⼀、概念与分类单⽚机⼜称微控制器(M icro C ontroller U nit),包含:中央处理单元、程序存储器、数据存储器、输⼊/输出端⼝1、按算术逻辑单元的位长度:4位机、8位机、 16位机、 32位机、64位机2、按内部结构(1)精简指令集RISC:提供较少的基本指令,执⾏效率较⾼(2)复杂指令集CISC :提供较多的指令,包括功能强⼤的指令(如乘除法),执⾏效率较低3、按编址⽅式(1)普林斯顿结构:指令与数据共⽤同⼀块存储器,共⽤地址/数据总线,同⼀时间只能对指令或数据操作(2)哈佛结构:指令与数据是分开的,各⾃独⽴的地址/数据总线,可同时对指令与数据操作⼆、单⽚机结构概述1、中央处理单元(CPU):(1)指令解码单元(IU)通过解码硬件电路去解析⼀连串⼆进制码以作为控制器的决策核⼼(2)执⾏控制单元(EU)接受IU所发出的指⽰,将各单元中的数据进⾏互换、传送、运算、判断,再依汇编指令所指定的动作或运算进⾏输⼊、输出、存储等⼯作(3)算术逻辑单元(ALU)可从指令集中实现算术和逻辑操作,ALU在接收相关的指令码后执⾏需要的算术与逻辑操作,并将结果存储在指定的存储位置2、程序存储器(ROM)内容⼀般不可更改的,⽤于存放⽤户代码的存储器,不同型号不同容量3、数据存储器(RAM)内容可更改的,⽤于存放单⽚机状态或⽤户变量的存储器,不同型号不同容量4、总线(BUS)⽤于内部各单元间信息互通,⼀般有3种总线:数据总线、控制总线、地址总线(1)数据总线:传送各单元间数据的硬件(2)控制总线: 控制单⽚机数据的读或写,使、除能某单元以接收或传送数据(3)地址总线: 主要⽤来寻址,指⽰数据存取的位置,即⽤地址总线寻址三、 HT合泰单⽚机结构分析(以HT48系列为例)1、时序和流⽔线结构(1)系统时钟由晶体/陶瓷震荡器或RC震荡器提供(2)指令周期由T1~T4 4个内部时钟组成,流⽔线结构保证指令在⼀个指令周期内被有效执⾏T1:程序计数器⾃动加1并抓取新指令T2~T4:完成解码、算术逻辑并执⾏功能(3)当程序计数器的内容改变时,如call调⽤或jmp跳转时,指令需要多⼀个指令周期取出当前指令地址的下⼀条指令,并清除流程,再⽤另⼀个周期去执⾏下⼀动作2、程序计数器(PC)(1)程序指令码的读取是由于内部有⼀程序计数器来寻址,在指令码被读取后程序执⾏期间,程序计数器指向下⼀条要执⾏的指令地址(2)复位起始地址是0000h,在每条指令执⾏后⾃动加1(jmp、call等除外) 3、堆栈(Strack)是存储器特殊的部分,在⼦程序调⽤或中断响应时,程序指针压⼊堆栈,返回指令(RET或RETI)使程序指针返回到上次⼦程序调⽤位置四、程序存储器(ROM)存放⽤户代码,内容为⼆进制机器码1、分类:掩模 \ OTP \ EEPROM \ FLASH2、⼀般为14Bit~16Bit,除了存放程序外也包含中断⼊⼝和数据表3、特殊向量地址(以HT48R50A-1为例):(1)复位向量地址: 000H(2)外部中断向量地址: 004H(3)定时/计数器0中断向量地址: 008H(4)定时/计数器1中断向量地址: 00CH五、数据存储器(RAM)1、可更改的8位内部存储器,⽤来存放临时数据,分为“专⽤寄存器”和“通⽤数据存储器”2、通⽤数据存储器(⽩⾊部分)3、专⽤寄存器六、专⽤寄存器1、间接寻址寄存器IAR0/IAR1在间接寻址寄存器上的任何动作,将对间接寻址指针(MP0/MP1)所指定的数据存储地址产⽣的读/写操作2、间接寻址指针MP0/MP1与IAR0/IAR1组成间接寻址操作功能3、累加器ACC所有ALU得到的运算结果都会暂时存储在累加器,数据传送也需要累加器4、程序计数器低字节寄存器PCL直接给PCL赋值将导致直接跳转到本页范围的某⼀地址。
--测试环境C 编译器V2Step Step over Step OutPov 痢 on Resrt也他我条1Reset ItemPower-On R^sctTarget Board ResetSoftware ResetConunandSoftwarePtJweT'On ResetCommandClciir Reaisiets (*) (*)(*)(*)Clem 7 (Options Yes NoNaNoClear PD. TO Yes Nc No Yes PCValut?(**) 0 0 0Bmulation Stop (**) No(***) Yes Yes Chetk Stand-AloneYesNo NaNo5-1拄意:(*):缓存器征不同舐克下所覺的影响』请奪雷备徹控制器的Df 曲BoM.(怜FC 值为伽同时停止醍件仿真.(杠*);假如虫戌来口 F •应用电舒板「则系统会在直鈕亢应后自动丿F 始谨件的肪戌。
2. Data TypeData type Size (bit) C compiler VISize (bit) C compiler V2Size (bit) C COMPILER V3Size (bit) ANSI Cbit 11N N char Q 3 8 0signed char 0 a 8nunsigned char 8a 8short816 16 诟unsigned sliolt a 16 16 16 | lot816 16 16unsigned ini 816 16 12Long16 32 32 32 unsigned long 16 32 3232 long longN N 32 64 unsigned long long N N 32 64 float N32 2432 double N32 32 64 long doubleNNN128:3..数组,支持一维/二维数组(大小小于1bank );4. 使用 const 关键字,变量将存储于程序存储区,如,const uint8_t tab[] =“1,2,3”;合泰单片机总结1. DebugToggie Bf^ak Port Qear All Bveat Poirt Ootoursor Stop5.中断服务函数:#pragma vector ISR_tmr0 @ 0x0c //定义中断入口地址void ISR_tmr0(void){tick++ ;}6.中断函数中调用普通函数(1)方法 1#pragma vector ISR_tmr0 @ 0x0c#pragma nolocal funfun(){}void ISR_tmr0(void){fun() ;}(2)方法 2#pragma vector ISR_tmr0 @ 0x0cfun(){}void ISR_tmr0(void){#asmcall _fun;#endasm}7.宏定义#define _pa0 _12_0 //bit 0 of RAM address 0x128. 位变量定义对于有多个bank 的MCU ,位变量只能定义在bank0 ,使用如下方式#pragma rambank0 bit flag ;#pragma norambank9.指针(1) 不支持指向“字符串数组”char *rain bow[] = { "red", "ora nge", "yellow" };// not supported (2) 只支持全局的静态函数指针,且所指函数不能带有参数 fun() {return 1; }in t (*c onst p)() =fun; // global and in itializati on required void mai n() { int a; a=(*p)(); }(3) 不支持取得con st 常量的地址 const int ldc = 0; void mai n(){ int *a;a = &ldc; // cannot pass }10.内嵌汇编■內嵌懒褊4怕他睨在鹵式內■内嵌集編只能撰寫描节・平能用来定義姿敷action 等一■內嵌駅菊中胸煥數,貼阳f 更用相血旳集編名.而逮敎何怕編名宇必冏的關保如h':• 總鴨煙Wft :V8r —»_var{超過•個糾:_var._ var[1J^ var(2],_ var(3]) 例:char a;long b; M.WJ ASM 名:日T_a, 圍」>罔 •同邯變1ft : CRTRR^CRS …C 超過'■' ^1: CR1. CR1[1)n CR1[2], CR1[3]),捷屮「吸位足按編譯阴疔:来冊列的.所以.如卑改醱厂迅我的怕序.仃可能帯編岔 就薯改噓T .而且貼吊建數嚏柯熾用過干會口相應的備編伞.Ltill r 上例屮的r 划畢沒有先賦帕r=0;刖會找不到CR4而報皓. 例:void fun{) <char aJong b; a = 0;b=0;打时祸 ASM r t - a -CR1, t)^CR2h CR2[ 1 ],CR2[2J,CR 2(3]}« 自:i 數 :ramefa, b) t^name( 跌十:獸科:named .name 1 ,name2--) 例:void fun{ctiar a .char b)會晒的 ASM 名:fun — fun, s-KfunO. b^furl• static 出現在内底整編内.冈勇它的烷編色址曲機的.«如果不知道鳞裁所對應的輩編勒H 可坦看廉出的asm 悄屮叭#pragma debug variable 8 2 CR1 d1其中d1 色數.CR1d 1冋打瞰削-翔昌名,當擂.要先彌鞍0跖才會產出asm fS.Eg: char a; int b; voidfun(char p1,int p2)#asm[label:] opcode [opera nds]#endasm{a = p1;#asm // b = p2;MOV A,fun1MOV _b,AMOV A,fun1[1]mov _b[1],A#endasm}void main(){int d1;char d2;unsigned char q, r;r = 0;q = d1 / d2; // get quotient #asm // r = q;MOV A, CR3 ; CR3 qMOV CR4,A ; CR4 r#endasm#asm // fun(d2,d1)MOV A,CR2MOV fun0,A ; p1 = d2MOV A,CR1MOV fun1,AMOV A,CR1[1]MOV fun1[1],A ; p2 = d1CALL _fun#endasm}11.预编译指令12.编译器特殊选项格式^pragma keyword [ options )臬垒keyword 卩丁肓options,長格列出pragma keywords①ROM bank HT4U6②凡具備多個RAM bank及只有-個ROM bank記憶體的黴控制器(例如HT82M99AE )此功能”有效3凡具備禺個RAM bank記悝閒的微控制器(例如HT46R63)此功能F有效•#pragma bp free#pragma bp nofree對於這兩個亦眩處埋指令所包含前麒述式(staternents),編譯器會將產出之指令碼中所有會改弊BP暫存器的指命11除,也就罡MOV BP T A指令不會產出-主要是牆減編譯產出的拾令码大小一前題是必須確罡變數所在的記憶缠皆是固定的RAMbank.從pragma bp_free之後的救述開始.直到#pragma bp_noltee盘iL可特兩個前置處理指會加在丽式中的任何敘述的册黴•#pragma function fiinctjon_name @rom_address権定祇ftincton_name安置於ROM記憶耐rom_address竝址處.rom_address可価用卜六進制,例如0x100代哀棍扁式放於ROM記憶證的256桂址處. 述果哪牧在RCM bank 1的256廿址.則將rom_address設:爲0x2100•#pngma nobp□對中謝服務涮武有或-指示鶴澤髀个夏TF中斷贸務函式中保存BP暫存務前內春-逼個拒命會對星-程式愴案內所口的中斷服務函式有效-#pragmo ncl0»l functk)n_name針對…般的函式一對於想定的蘭式” hindion_name在鵜澤時將函式使用到的厨部费敕與內『暫存髀皆謎成•纓型匪英變數,而和會與荔他變數4£^RAM記憶空間的共用型態(commontype). 口里中詬般務爲式會呼其也函式時,這些被呼叫为函式中便用旳石部或內部耋數若與共他函式共用RAM空間.苜有宾料披礦壇的乐瞼•逗個前置處理指命將排除逗極風瞼.-#pngma nompO#pngma nompl只對中詬服務函式有效.指示編譯SS不變在中斷服務函式中保存MP0或MP1暫存痔的內容.這個播书會對軍-程式粽案內所百的中斷服務函式有效舉譯番會根據議控制器的袈情決定卮否在中斷服務函式內保存BP r MP0r MP1暫存器的內容•#pragma nmbankO#pragma norambsnk慨童數存放在RAM bank 0的空閭內.所有宦義在這兩個前匿堪理指令內的蚩數皆被安S卡秤RAM bank 0空間.E畏悄控制器只昱僑個RAM bank,則不需夏頑用須個捐塔.如杲黴控制器具有一WTX上酌RAM hank時•可以使用.若釁數足bit資料型態時,則貼須要將變數定義在RAM bank 0之中-#pragma roimbankO#pr^gnna noromb^nk將函式般许蓟ROM bankO內.所有定義於运兩厢丽竇电理描命中的函式皆被安賈ROM bank □的空間內flinction_name2 [, ..J-#pragma roimbank banknum function namel [r适個忙直喘埋橫令首將所卷走菟函叢安蚩?F描定的ROM bank寺中一怕nknum是ROM gnK的肩睨,叫依據微控制器叭ROM Z桶〕殳定广.ftjnction_name 1 ,function_nanne2层两式名‘可以同特指定-個IX I■的兩式--#pragma vector isr name ©vector address宣告中斷眼務函式晞字及中斷向五-樹冲畑務施式MSB先宜告一isr_name是葩名稱.vector_address星中謝向量數伯•#pragma novectomest指示中斷服務函式中,保留曹存暮的記憶空間只有一組.當微控制譽的中斷事件不允許重!ft 囊生,磁須處理完成前一個广緩才能Bfi理卜個時丫使用此前置處理指令可以IB眷資料記憶空111] (RAM space),避鬼RAM bank 0 的空間滿龍(overflow)旃辱閹47節中斷锲務函式昂說明13.内嵌函数■ n接組譯成組合藉诗指令的內建碉式C函式組合語吕带令碼(assembly instruction)void _clrwdt{) CLR WDTvoid_clrwdt1( )CLR WDT1void _clrwdt2() CLR WDT2void _halt() HALTvoid _nop() NOP■其他內建储迓void_ir(char*p)將抬橈p抬到的位元紐(1 byte)向右旋轉--個位元(bit) 例如’ ch = CxA5 ; _rr(&ch);則ch = 0xD2¥oid」「「(int *pl)將指標pl指到的字元組(2 byte)向右旋轉一個位元(bit) 例如T ent 匸0xA5A5; Jrr(&cnt);則ent = 0xD2D2void_i1 (char *p) 指標p指到的位元組(1 byte} I旬左旋轉一個位元(bit) 例如,ch = OxAS ; i_rl (&ch);則ch ■ 0x4Bvoidjrl (int *pl)將拒權"pl指到的字元組(2 byte)向九碇轉-個位元(bit) 例如.ent = 0xA5A5 : _lrl (&cnt);則ent = 0x4B4Bvoid _swap(char *p)將帛標p扌旨创的位元組(1 byte}四個低位元與叫個馮位元互換例如(ch = 0xA5 ; swap (&ch);則ch = 0x5Avoid _dela.y(unsigned long tick)延時tick 個指令週期(instruction cycle)tick <= 263690,若tick = 0,則表示無限延時(infinite loop)14.刃外.标头档(h)屮宦义的符号口旺._pdf与to皆不婴便用. 例如r iflf c ) a - ah + bh + ];就是不好的耳法°。
Holtek 微控制器應用範例–使用Holtek C 語言目錄第一章內容簡介第二章選定Holtek C 語言的使用環境2.1 進入HT-IDE3000 建立新的專案時, 選定Holtek C 編譯器2.2 已開啟專案後, 選用Holtek C 編譯器第三章微控制器C 語言程式的速成3.1 定義主函式main()3.2定義副函式(sub-function)3.3定義全域變數(global variable)3.4定義中斷服務函式(Interrupt Service Routine : ISR)3.5 其他第四章 C 語言程式4.1 C 程式架構4.2 開始用C 語言設計一個程式4.2.1 定義主函式main4.2.2 將標頭檔引入(include a header file)4.2.3 定義文字符號及變數4.2.4 設定微控制器及裝置的初始狀態4.2.5 設計子函式4.2.6 設計中斷服務函式4.3變數(variable) 及資料型態(data type)4.3.1 變數名4.3.2 資料型態4.3.3 變數的有效範圍(scope)4.3.4 變數的資料型態(data type)整數型(integer)浮點型(floating point)4.3.5 bit 資料型態4.3.6儲存類別(storage class) 與修飾詞(qualifier)儲存類別(storage class)修飾詞(qualifier)4.3.7絕對變數(absolute variable)4.3.8常數(constant)4.3.9指標(pointer) 與陣列(array)指標的運算子& 與*陣列(array)4.3.10結構(struct) 與等位(union)結構的運算子-> 與.4.4運算子(Operators)運算前的型態轉換4.5程式流程控制(program flow control)4.5.1if-else 敘述4.5.2switch 敘述4.5.3for 敘述4.5.4while 敘述4.5.5do-while 敘述4.5.6goto 敘述4.5.7break 與continue 敘述4.6函式(Functions)4.6.1參數(arguments)4.6.2返回值(return values)4.7中斷服務函式(Interrupt Service Routines)4.8在C 語言程式中嵌入組合語言(in-line assembly code)從組合語言的程式去存取 C 語言的物件(變數)4.9前置處理指令(Preprocessor)4.9.1 定義文字符號(#define)4.9.2引入檔案(#include)4.9.3內嵌組合語言(inline assembly)4.9.4 條件式編譯(#if/#endif)4.9.5 編譯器的特殊選項pragma4.10Holtek C 編譯器的內建函式(built-in functions)第五章基本 C 語言程式5.1 語法觀念5.2 迴圈的應用(loop)5.3 撰寫MCU 應用程式的注意事項5.4 可供微控制器應用程式使用的範本5.5 設計微控制器應用程式的小技巧第六章程式範例–初級6.1LED 跑馬燈6.2LED 霹靂燈6.3 單顆七段顯示器6.4 5*5 點矩陣LED 顯示6.5 HT48 微控制器控制HT1621 LCD 的顯示6.6 HT48 微控制器控制LCD 模組的顯示6.7 具LCD 驅動功能的微控制器之顯示應用程式– HT46R636.8 顯示器的通用函式– HT44780 LCM6.9 鍵盤掃描程式第七章程式範例–中斷函式7.1 用時鐘控制LED 的亮與滅7.2 類比/數位轉換(ADC) 的應用第八章HT46R52A 應用於鎳氫電池充電器(HA0084T)第九章程式範例– HT46R74D-1 胎壓計(HA0105T)第一章內容簡介盛群半導體公司(Holtek)開發一系列的八位元微控制器(micro-controller, MCU). 當開發微控制器的應用程式時, 除了可使用盛群提供的組合語言(assembly language),也可使用標準的C 語言編譯器(C compiler).由於八位元微控制器的記憶體空間, 不論是程式記憶體(program memory space)或是資料記憶體(ram memory space), 皆是有限制的, 通常會使用組合語言開發應用程式. 但是越來越多的微控制器支援更多的記憶體以及更多的功能, 使得程式也相對的擴大. 如果仍然使用組合語言開發程式, 不但費時費力, 未來在維護及擴增功能的工作上也相當困難.因此, 使用高階程式語言, 例如C 語言, 來開發應用程式就是一種可行的趨勢.C 語言是高階程式語言中的一種, 它具有高度的的可讀性及可移植性(portability),除了能夠快速地完成應用程式的開發與偵錯, 也很容易移植到其他的微控制器上. 當程式需要縮減或擴充功能時, 也很容易的完成, 因此很適合於微控制器的程式開發.本書主要是以Holtek C 語言為主, 說明如何使用Holtek C 語言撰寫盛群微控制器的應用程式, 包括 C 的程式架構, C 語言的一般用法, 特殊用法及應用範例書中將說明在開發微控制器的應用程式時需要注意的地方及如何撰寫會比較恰當, 並配以實例解釋.讀者可以參考修改或直接採用到自己的程式中, 再用發展工具HT-ICE, HT-IDE3000 驗證之.第二章介紹選用Holtek C 編譯器的步驟, 指引HT-IDE3000 呼叫Holtek C 編譯器去編譯C 語言的原始程式.第三章提供一種快速撰寫 C 程式的方法, 對ANSI C 語言熟悉的用者, 可於閱讀本章之後即開始撰寫微控制器的 C 語言程式第四章介紹C 語言, 未曾使用過 C 語言的讀者應仔細閱讀本章以了解 C 語言的用法第五章介紹使用 C 語言寫程式的基本觀念, 注意事項及建議的寫作方法第六章到第九章則是應用範例, 針對盛群各系列的微控制器, 以 C 語言撰寫的應用程式. 包含有功能說明, 應用電路及程式說明.文件編號版別 1.20日期2008/5/26 第5 頁共189 頁第二章選定Holtek C 編譯器的使用環境2.1 進入HT-IDE3000, 建立新的專案時, 選定Holtek C 編譯器進入HT-IDE3000 開發環境後, 依照下列方法建立一個新的專案(project)→ 移動滑鼠游標到Project 選單, 按左鍵→ 移動滑鼠游標到New 命令, 按左鍵→ 出現如下的視窗, 在Language Tool 之處勾選Enhanced Holtek C compiler/Assembler文件編號版別 1.20日期2008/5/26 第6 頁共189 頁2.2 已開啟專案後, 如何選用Holtek C 編譯器若專案(project) 已開啟之後, 可以點選(click) Option 選單下的Project Setting 命令,在Language Tool 中點選Enhanced Holtek C Compiler/Assembler 以設定使用Holtek C 的Enhance 版編譯器Enhance 版的C compiler 包括ehcc32srsc.exe , ehcc32mrsc.exe 與ehcc32mrmc.exe 三個執行檔此版本必須在HT-IDE3000 V7.0 或以上的系統才能執行第三章微控制器 C 語言程式的速成本章介紹如何快速撰寫微控制器的 C 語言應用程式. 已熟悉ANSI C 標準語言的用法或有撰寫的經驗者, 在閱讀此章後即可開始設計撰寫微控制器的 C 應用程式, 以下各節是基本的C 程式成員, 某些是必須要有的, 如3.1, 其他的則視微控制器的功能及應用來決定是否需要3.1 定義主函式main()#include “ht46r63.h”void main(void){int Flag ;……TurnOn_LCD() ;Flag = LCD_display(cstr) ;TurnOff_LCD() ;……}主函式的返回資料型態(return type)必須是void, 而且不能有參數檔案ht46r63.h 定義與微控制器有關的常數, 例如暫存器的位址定義, 將之引入(include) 可增加程式的可讀性.3.2定義副函式(sub-function)視程式的大小及功能決定是否需要定義副函式. 基本上, 主函式應將應用程式的架構做成模組化, 不需要將所有的程式皆放在主函式中. 為了能很快的完成及了解應用程式, 主函式中只需要包含(呼叫) 定義各功能的副函式即可, 無論在設計或維護程式時皆能很快的進入與完成.例如, 關於LCD 的開啟, 顯示及關閉等功能就可分別定義為單獨的副函式, 如下例. 任何其他的函式或其他的應用專案都可去呼叫這些副函式. 若設計成通用型的, 也可藉由程式館管理器(Library Manager) 將之建入程式館檔案, 以供其他應用專案使用.void TurnOn_LCD(void){}int LCD_display(char *cstr){}void TurnOff_LCD(void){}3.3定義全域變數(global variable)程式在運行中會需要一些變數做為資料存放的地方, 由於微控制器資料記憶體大小的限制及C 編譯器的設計, 最好將常需使用的變數定義為全域型的變數, 在編譯程式的大小與執行上皆較佳. 例如定義常數型指標變數cstr 指到字串“Hello!”, 則可如下const char *cstr = “Hello!” ;3.4定義中斷服務函式(Interrupt Service Routine : ISR) 若微控制器的周邊裝置具有中斷功能,程式也需要此中斷機能以完成工作時, 則必須定義此周邊裝置的中斷服務函式(Interrupt Service Routine, ISR), 如下的格式#pragma vector ISR_tmr0 @ 0x0cvoid ISR_tmr0(void){tick++ ;}中斷服務函式必須遵守下列規定→ 返回的資料型態必須是void→ 不能有參數(必須為void)→ 必須使用前置處理指令#pragma vector 設定中斷向量值(interrupt vector), 在函式名稱(本例子是ISR_tmr0) 之後加上@ 及中斷向量值(本例是0x0c). 也可使用先前定義好的常數, 例如#define VECTOR_TMR0 0x0c#pragma vector ISR_tmr0 @ VECTOR_TMR0void ISR_tmr0(void){}3.5 其他上述的主函式, 副函式及中斷服務函式不需要定義在同一個原始程式檔案內. 為縮短編譯的時間, 最好是分別定義在不同的檔案中, 並使用有意義的檔名, 方便日後找尋所要的函式.第四章 C 程式語言基本上, Holtek C 是仿ANSI (美國國家標準局) 標準的 C 語言, 為配合盛群八位元微控制器的架構, 將提供一些特殊的語法去存取或控制微控制器的資源. 另外, 本章會從八位元微控制器的角度, 說明如何使用 C 語言設計及撰寫微控制器的應用程式4.1 C 程式架構C 語言的程式是由敘述(statements) 所組成, 每個敘述的最後必須有分號‘;’ 做為結束符號.敘述分為四類:→ 宣告(declaration), 宣告變數及資料型態, 資料結構.例如char flag, tick_cnt ; // 宣告變數flag 與tick_cnt 為char 型態→ 定義(definition), 定義變數數值及位址例如int total = 10 ; // 定義變數total, 設定值為10→ 描述式(expression), 執行數學及邏輯運算, 控制程式的流程例如count = ( input > 10) ? 10 : input ;→ 函式呼叫(function), 執行函式的功能例如putchar(ch) ; // 寫出一個字元到輸出口每個敘述可以附加註解做說明. C 編譯器不會對註解做編譯, 下列為兩種可被接受的註解→ 介於符號/* 與符號*/ 之間的數據及文字, 包括換行字‘\n’如果/* 與*/ 不在同一行, 則其間所有的行皆會被視為註解例如/* this is a comment 1 */→ 從符號// 開始到本行的結束皆被視為註解例如// 這是註解的新寫法在 C 語言中, 程式執行區(program block)是以函式的格式定義, 因此, 所有要執行的敘述皆需定義(包含)於某個函式(function) 中, 例如描述式.4.2 開始用C 語言設計一個程式依照下列步驟¸使用 C 語言實作一個簡單的應用程式4.2.1 定義主函式main範例void main(void){}在 C 語言中, 主函式main 是程式執行的起點, 有如組合語言程式中的startORG 00jmp startstart :void 是資料型態, main 與void 皆是保留字, 必須用此字, 小寫字母4.2.2 將標頭檔引入(include a header file)範例#include “ht46r63.h”// 引入標頭檔ht46r63.hvoid main(void){}標頭檔ht46r63.h 中定義許多與微控制器有關的變數及文字符號(symbol). 接下來寫程式時可以使用這些變數與文字符號(symbol), 好處是寫程式或維護程式時會很容易了解程式的功能, 增加程式的易讀性. 例如unsigned char _pa @0x12 ;定義_pa 是一個unsigned char 型態的變數, 它的位址在RAM 的0x12 (就是A埠, port A). 所以程式中如下的敘述_pa = 0 ;則與組合語言的CLR PA ; (PA=[12H]) 有相同的功能4.2.3 定義文字符號及變數在程式中使用文字符號能夠更容易的讀懂程式及修改, 例如定義文字符號_pa0 如下#define _pa0 _12_0表示_pa0 是RAM 位址12H 的位元0 (bit 0), 就是 A 埠的位元0. 下列敘述_pa0 = 1 ;表示將 A 埠的位元0 設為1, 與組合語言程式的SET [12H].0 有相同的功能前置處理指令#define 是定義一個文字符號代表數值, 或是文字串, 或是巨集指令.C 編譯器的前置處理器(preprocessor) 在編譯前, 會先替換這些定義的文字符號.前置處理指令#undef 是將先前定義過的文字符號取消, 變成無效. 詳細的說明請參閱第 4.9 節微控制器中其他暫存器的變數或文字符號, 皆定義於對應之微控制器的標頭檔案內, 在設計程式時可參考之. 可以定義一些程式需要, 但是在標頭檔案中沒有定義的變數或文字符號, 方便程式的開發及維護, 例如#include #define “ht48R50A-1.h”scl _pa3 // SCL (時鐘線) 接到MCU 的A 埠的第3 位元#define scl_c _13_3 // A 埠之控制暫存器的第3 位元(bit 型變數)#define sda _pa1 // SDA (資料線) 接到MCU 的A 埠的第1 位元#define sda_c _13_1 // A 埠之控制暫存器的第1 位元void main(void){}定義四個文字符號scl, scl_c, sda, sda_c 分別代表不同的輸出/輸入埠定義變數會佔用RAM/ROM 的空間, 如果又指定位址, 則此變數佔用此位址, 否則Linker 在做連結時才會分派位址給變數. 其效果有如組合語言的_pa DB ?定義文字符號的效果則與組合語言的EQU 相同, 例如#define scl _pa3 與scl EQU _pa3有相同的效果4.2.4 設定微控制器及裝置的初始狀態根據程式的功能, 設定微控制器中各裝置的初始值, 例如周邊設備的初始狀態, 暫存器的型態等.scl_c = 0 ; // 設定SCL (= PAC) 的狀態為輸出sda_c = 0 ; // 設定SDA (=PA) 的狀態為輸出4.2.5 設計子函式獨立之功能可分別用子函式完成, 在程式的偵錯, 維護及重複使用上皆有好處. 在設計時需要注意函式的參數,返回值等. 通常會將主函式main() 放在程式檔的最後, 各個子函式定義在前面或其他的程式檔案內. 下列範例只是部份, 詳細的說明可參閱4.6 節.#include “ht48r50a-1.h”// 引入標頭檔#define scl _pa3 // SCL (時鐘線) 接到MCU 的A 埠的第 3 位元#define scl_c _13_3 // A 埠(位址0x13)之控制暫存器的第3 位元(bit 型變數) #define sda _pa1 // SDA (資料線) 接到MCU 的A 埠的第1 位元#define sda_c _13_1 // A 埠(位址0x13)之控制暫存器的第1 位元// 函式: StartCondition() 子函式// 功能: 開始一個命令// 輸入: 無// 輸出: 無void StartCondition(void){sda = 1 ; // SDA 輸出highscl = 1 ; // SCL 拉highsda = 0 ; // SDA 輸出lowscl = 0 ; // 完成Start of command}// 函式: StopCondition()// 功能: 結束先前的命令// 輸入: 無// 輸出: 無void StopCondition(void){}// 函式: main()// 功能: 主函式// 輸入: 無// 輸出: 無void main (void){unsigned char Rdata, type ;// 暫存器的初始設定scl_c = sda_c = 0 ; // 將A 埠的位元1, 3 設為輸出型態(SCL, SDA 為輸出)StartCondition() ; // 呼叫子函式……}4.2.6 設計中斷服務函式針對有硬體中斷的微控制器, 需要設計中斷服務函式以處理中斷事件定義周邊裝置的中斷服務函式(Interrupt Service Routine, ISR) 如下格式#pragma vector ISR_tmr0 @ 0x0cvoid ISR_tmr0(void){tick++ ;}中斷服務函式必須遵守下列規定→ 返回的資料型態必須是void→ 不能有參數→ 必須設定中斷向量值(interrupt vector), 在函式名稱(本例子是ISR_tmr0之後加上@ 及中斷向量值(本例是0x0c). 也可使用先前定義好的常數, 例如#define VECTOR_TMR0 0x0c#pragma vector ISR_tmr0 @ VECTOR_TMR0void ISR_tmr0(void){}4.3變數(variable) 及資料型態(data type)程式執行過程中, 可能會需要暫存一些資料, 例如旗標, 執行次數, 延遲秒數等, 因此就必須定義變數以儲存這些資料. 由於變數要佔用程式記憶體(PROM) 或資料記憶體(RAM), 因此在使用變數之前, 定義變數的資料型態, 以便讓編譯器正確的編譯程式及配置記憶體空間.除了資料型態之外, 還可加入儲存類別(storage class) 及修飾詞(qualifier), 對變數做更詳細的安置.4.3.1 變數名變數名的規則→ 第一個字元必須是英文字母或底線符號(underscore), 之後可緊接著字母或數字→ 變數名的前32 個字元有效→ 變數名內不可有+, - , *, / , ……等符號字元→ 英文字母的大小寫是有區別的(case-sensitive), 例如count 與Count 是不同的變數名範例, number, total_tick, _tick 是合法的變數名, 而2num, $dot, line\n 是非法的變數名4.3.2 資料型態* float, double 皆使用IEEE754 32 位元的格式4.3.3 變數的有效範圍(scope)根據變數定義的所在¸決定此變數的有效範圍. 可分為→ 區域變數(local variable)定義在程式區塊內(program block, 例如函式)的變數皆是區域變數. 只有當此程式區塊被執行時, 區域變數才會有效, 而在執行完畢並離開此程式區塊後, 這些區域變數將無效. 程式區塊是指包含在左右大括號‘{‘ 及‘}’ 之間的敘述行定義在函式中的static 變數則是全域變數, 參考 4.3.2 說明→ 全域變數(global variable)定義在所有函式之外的變數為全域變數. 當程式在執行時, 此變數皆有效, 任何函式都可以存取或修改這個變數範例#include “ht48r50a-1.h”unsigned char flag ; // 全域變數void main(void){ char type ; // 區域變數, 只有在此函式被執行時才有效static status = 0 ; // static 變數, 只在第一次執行時設為0……}4.3.4 變數的資料型態(data type)當宣告變數時,必須指定它的資料型態, 以告知編譯器此變數所需記憶體的大小. 資料型態分為整數型(integer type)及浮點數型(floating point type). 整數型又可區分為有正負號(signed) 及無正負號(unsigned).整數型(integer)→ char佔用一個位元組(byte) 的記憶體空間. 如加上signed 則表示有正負號, 其大小範圍是–128 到127. 若加上unsigned, 則表示沒有正負號, 其大小範圍是0到255. 如果沒有signed 或unsigned, 則被視為signed. 可用此型態定義字元,如‘A’, ‘d’, ‘$’, ‘3’等→ short佔用兩個位元組(2 bytes) 的記憶體空間, 如加上signed 則表示有正負號, 其大小範圍是–32768 到32767. 若加上unsigned, 則表示沒有正負號, 其大小範圍是0 到65535. 如果沒有signed 或unsigned, 則被視為signed.Holtek C 採用little-endian 格式, 就是變數的低位元組(least significant byte) 存放在記憶體的低位址. 例如變數count = 0x1234 是存放於記憶體40H 的位址, 則低位元組的數值0x34 存放於位址40H, 高位元數值0x12 存放於位址41H.→ int與short 型態相同→ long佔用四個位元組(4 bytes) 的記憶體空間, 如加上signed 則表示有正負號, 其大小範圍是–2147483648 到2147483647. 若加上unsigned, 則表示沒有正負號, 其大小範圍是0 到4294967295. 如果沒有signed 或unsigned, 則被視為signed在little-endian 格式中, 32位元的變數, 則是先存低字元(least significant word) 的低位元組(least significant byte)到記憶體的低位址, 再存放低字元的高位元組(high byte), 再存放高字元(high word)的低位元組, 最後才是高字元的高位元組浮點型(floating point)Holtek C 支援IEEE 754 32 位元的格式. 包括float 及double 兩個資料型態, 浮點數值是以下表的格式儲存在記憶體與浮點數值的關係式為number = (-1)sign x 2(exponent – 127) x 1.mantissa例如, 浮點數為 2.77000e+37 在儲存到記憶體時換成7DA6B69B 共佔32 位元4.3.5 bit 資料型態類似整數型, 但是只有0 或 1 兩個值, 所以只會取整數的最低位值(LSB:least significant bit) 需要注意下列用法→ bit 型態不可與auto 一起使用, bit 型態的變數不可當函式的參數, 不可用於指標(pointer) 的數據型態, 不可設定靜態初始值(static)→ bit 型態可以設為函式的返回型態, 它是存於累加器(accumulator) 的相對位置→ 程式開始執行時, 不會設定bit 型變數的初始值, 因此程式必須自行設定初始值→ 以下是合法的使用方式static bit init_flag ; // 定義於函式內則被視為區域變數bit toggle_flag ;→ 範例int data = 0x54 ;bit flag ;flag = data ;則flag = 0 (取data 的LSB)如果微控制器具有一個以上的RAM bank, 例如HT46R63, 在定義bit 型態的變數時需要使用前置處理指令#pragma rambank0 指定在RAM bank 0, 如下#pragma rambank0bit flag ;#pragma norambank4.3.6儲存類別(storage class) 與修飾詞(qualifier)變數於宣告或定義時必須指定其資料型態, 但是儲存類別及修飾詞是可選擇的, 可根據應用時的需要去設定或不使用.儲存類別(storage class)儲存類別與區域變數(local variable)及全域變數(global variable)有關.→ 儲存類別autoauto 是給區域變數使用的, 沒有指定儲存類別的區域變數皆是auto寫與不寫auto 都是相同效力. 區域變數是存放在RAM bank 0 的空間→ 儲存類別registerregister 與auto 類似, 是給區域變數用的, 當變數的存取很頻繁時, 可將之設為register, C 編譯器會使用暫存器而非資料記憶體空間來存放此變數, 如此可增加存取的速度及減少編碼. 目前並未實做此功能.→ 儲存類別staticstatic 的變數會一直有效到整個程式結束後才失效. 它的初始值只會在程式開始執行時被設定一次. 雖然static 的變數在程式結束前皆有效, 但是定義在函式內的static 變數仍然是區域變數, 必須要在它所定義的函式中才可以讀寫→ 儲存類別externextern 通知C 編譯器此變數是定義在其他的程式檔內, 需要經由連結器(Linker)連結定義此變數的檔案後, 才知道變數的所在.以目前在微控制器的應用程式上, 比較需要使用extern, 其他三種不具特別的優勢可用定義全域變數(global variabl)的方式即可達到相同效果. 建議不要使用.修飾詞(qualifier)→ 修飾詞constC 編譯器會將const 的變數放置於程式記憶體(PROM). 在定義const 變數時, 必須要設定其值, 而程式在執行中不能修改此變數的值→ 修飾詞constant這個修飾詞是Holtek C 編譯器特別提供的. 它會將constant 的變數放置於程式記憶體(PROM) 的最後一頁(last page). 定義constant 變數時,必須要設定其值, 而程式在執行中不能修改此變數的值. 使用此修飾詞要注意下列三點●只能使用在int 或unsigned int 的資料型態●設定值必須配合微控制器程式記憶體的寬度, 例如, 若使用在 HT48R50A-1 時,因為此微控制器的寬度為 15 個位元, 最高位元是無效的, 所以 0x9A 會被 C編譯器改成 0x1A. 最高位元, 位元 15 被清除為 0● 所有設定此修飾詞的變數或陣列, 總共佔用的字位元組 (word) 不可超過 256 個指定詞(specifier)→ 指定詞typedeftypedef 是針對資料型態做新名稱的宣告, 不是宣告資料型態的新變數, 而是宣告一個新的名字. 例如將UCHAR (新名字) 宣告為unsigned char 的資料型態, 可使用typedef unsigned char UCHAR ; // UCHAR 為unsigned char 的新名字UCHAR count ; // 變數count 的資料型態為unsigned char// 等同於unsigned char count ;使用typedef 宣告資料型態的新名字可以讓程式的可讀性更高, 更易了解. 例如,typedef unsigned int WORD ; // 使用WORD 代表unsigned int, 16 bitstypedef unsigned long DWORD ; // DWORD 代表32 bit 的double word4.3.7絕對變數(absolute variable)可以將全域變數或static 變數指定一個固定的記憶體的位址, 例如unsigned char PortA @ 0x12 ;在變數名的後面再加上‘@’及位址C 編譯器在編譯時會將程式中出現絕對變數的程式改為此位址, 但並未在記憶體中保留位置給此變數, 所以從連結器(Linker) 產出的對映檔(map file)中找不到此變數 C 編譯器會將之翻成組合語言的EQU 指令,如下_PortA EQU 12h此種用法主要是對微控制器內的暫存器做定義, 方便閱讀程式4.3.8常數(constant)整數型常數(integral constant) 可使用基底(radix)格式表示之.若常數的最後一字為l 或L, 則表示它使用signed long 或unsigned long 的型態. 字尾是u 或U, 則表示常數為unsigned 型態.浮點型(floating point)常數的型態是double, 若它的字尾是 f 或F, 則是float.字元常數(character constant)必須以單引號‘ ‘ 框住, 例如‘a’字串常數(string constant) 必須以雙引號“ “ 框起, 例如“Hello!”. 字串常數的定義會影響它所儲存的記憶體位址, 如下char *cp = “one” ; // C 編譯器會發出錯誤const char *sptr = “Hello” ; // “Hello” 儲存在程式記憶體(PROM) 常數型的變數或陣列(array)必須要設定其值, 否則C 編譯器會發出錯誤訊息,如上例4.3.9指標(pointer) 與陣列(array)指標本身是一個變數, 它的內容是另一個變數存放的位址, 類似組合語言的間接定址.在使用上, 指標必須要指到一個已定義(存放於記憶體) 的變數, 否則在程式執行時會發生錯誤. 指標的宣告格式資料型態*指標名[, *指標名,….] ; 資料型態是這個指標所指的變數的資料型態, 例如char. 指標名類似變數名, 可以在一行中, 宣告指向相同資料型態的不同指標名, 例如char *tptr, *array_ptr ;int *line_ptr ;以上只是宣告指標變數, 必須要將這些指標指向已定義的變數才能使用指標的運算子& 與*運算子& 如果緊鄰在變數的前面, 例如&line, 則是代表取得此變數的記憶體位址例如,int line ; // 定義變數int *line_ptr ; // 宣告指標line = 12 ;line_ptr = &line ;若變數line 被安置於RAM 的位址64, 則指標line_ptr 等於64運算子* 緊鄰指標變數之前是表示取得這個指標指到的變數的內容, 承上例, int total ; // 定義變數total = *line_ptr ; // 取得指標line_ptr 所指到的變數line 的內容則變數total 等於12指標的大小會根據微控制器具有之記憶體空間大小而定, 如果微控制器具有一個以上的RAM bank, 則指標本身會使用兩個位元組來儲存被指到的變數的位址如果變數有const 或constant 修飾詞, 則是指向程式記憶體(PROM), 而且此變數的內容不能被修改. 如果所指向的變數不具有const 或constant, 則指標會指向資料記憶體(data memory, RAM) 內的變數.陣列(array)陣列是由相同資料型態的元素組成的, 例如char array_name[32] ;是由32 個char 型態的元素組成的, 這些元素的名字是以陣列名array_name 為準, 而以索引(index) 區分各個元素, 例如array_name[3] 是第 4 個元素. 陣列的索引是正整數, 從0 開始直到元素的總個數減一, 上例中, 最後一個元素是array_name[31]. 這種資料型態在建表格(table) 時非常有用陣列也可當做指標的一種, 只是使用時格式不同, 下列範例說明指標與陣列之間的使用方法char *nptr, *fptr ; // 宣告指標char ch, tbl ; // 定義變數char table[5] = { ‘a’, ‘b’, ‘c’, ‘d’, ‘e’ } ; // 定義陣列nptr = table ; // 指標nptr 指到陣列table 的第一個元素table[0]ch = *nptr ; // 將字元‘a’ 存入變數chtbl = table[0] ; // 將字元‘a’ 存入變數tbl , 所以變數ch 與變數tbl 的內容相同fptr = &table[4] ; // 指標fptr 指到陣列table 的第5 個元素, table[4]ch = *fptr ; // 將字元‘e’ (第5 個元素) 存入變數ch 內tbl = *(nptr+4) ; // nptr 指到陣列table 的第一個元素, 加4, 所以tbl = ‘e’4.3.10結構(struct) 與等位(union)結構是一個或多個成員的集合, 每個成員的資料型態可以不同, 並且使用結構的名字去讀寫這些成員. 結構的宣告是等同於定義一個新的資料型態, 當變數宣告為一個結構的型態時, 便可用結構的名字去讀寫各成員的內容.成員的資料型態不可以使用bit 型態, 但是可以用bit-field 方式宣告成員的型態, 例如struct str_name {unsigned flag : 1 ; // 此成員放於最低位元least significant bitunsigned no_used : 7 ;unsigned stack : 5 ; // 此成員置於最高位元high bits} usage ;每個bit field 會置放於16 位元的單位內, 不會橫跨兩個16位元的單位等位(union) 的格式與結構相同, 唯一不同的是記憶體空間的分配方式. 等位是安排共用的空間來存放不同資料型態的成員. 每個成員必須要宣告其資料型態, 而等位的大小則是所有成員中佔用最大位元組(bytes)的型態大小. 每個成員的開始位址皆相同, 就是等位的位址.union union_name {char num_byte ; // 佔用1 個位元組。