详细的HT-IDE3000使用手册可以在HT-IDE3000中直接打开:帮助->Holtek HT-IDE3000使用手册。
HT66F018的数据手册可在Holtek官网自行下载,也可点击此处下载。
工程创建好之后,通过:工具->配置选项,可对系统的工作电压、时钟源、频率等进行修改。
本例程的配置:
SMOD寄存器在上电复位后的初始值为0000 0011,本程序不再对其修改,故最终的时钟是使用内部高速时钟:8MHz。该寄存器的详细信息在datasheet中工作模式和系统时钟一节。
端口配置不外乎输入/输出模式的选择,以及上拉电阻的配置。合泰的头文件HT66F018.h中,所有寄存器都是以“_”开头,使用小写字母。
_acerl = 0; //disable all AD
//PA口配置
_pac = 0x68; //0110 1000
_papu = 0x08; //0000 1000
_pa = 0x04; //0000 0100
_pawu = 0x0; //禁止PA唤醒功能
//PB口配置
_pbc = 0x07; //0000 0111
_pbpu = 0x00;
_pb = 0x00;
//PA0口拉高
_pa0 = 1;
//判断PA3口的端口电平状态
if (0 == _pa3)
A/D 转换控制寄存器的上电初始状态默认PA4-PA7, PB0-PB3 为模拟信号输入引脚,但A/D 转换功能并没自动开启。因些需注意若要将PA4-PA7, PB0-PB3用作数字信号输入引脚,或其它功能,需在程序中修改A/D 转换控制寄存器值以关闭A/D 功能。另外需注意A/D 通道使能,内部上拉电阻将自动断开。
HT66F018包含3 个TM, 分别命名为TM0,TM1 和TM2。每个TM 可被划分为一个特定的类型,即简易型TM(CTM),标准型TM(STM) 或周期型TM(PTM)。
下面提供使用TM0定时1ms,TM1定时200us的配置代码:
_cpc = 0x08; //关比较器
_tmpc = 0; //禁止TMn输入/输出引脚
_tm0c0 = 0x00; //TM0时钟为系统时钟4分频(Fsys=8M),则TM0时钟为2M,并关闭定时器
_tm0c1 = 0xC1; //定时/计数器模式模式,比较器A匹配(即16位比较)
_tm0al = 0xD0; //定时器T0赋初值,定时1ms
_tm0ah = 0x07;
_tm1c0 = 0x00; //TM1时钟为系统时钟4分频(Fsys=8M),则TM1时钟为2M,并关闭定时器
_tm1c1 = 0xC1; //1100 0001 定时器模式,比较器A匹配
_tm1al = 0x90;
_tm1ah = 0x01; //定时器T1赋初值,定时200us
简易型TM 核心是一个由用户选择的内部或外部时钟源驱动的16 位向上计数器,它还包括两个内部比较器即比较器A 和比较器P。这两个比较器将计数器的值与CCRP 和CCRA 寄存器中的值进行比较。CCRP 是8 位的,与计数器的高8 位比较;而CCRA 是16 位的,与计数器的所有位比较。
定时器的功能比较复杂,其他模式的配置请自行参见datasheet中的介绍。
HT66F018提供多个外部中断和内部中断功能,外部中断由INT0~INT1 引脚动作产生,而内部中断由各种内部功能,如定时器模块、比较器、时基、LVD、EEPROM 和A/D 转换器等产生。
下面提供的代码接上一节定期器的内容,使能定时器T0和T1的中断,同时打开外部中断0:
_integ = 0x03; //外部INT0中断双沿控制
_intc0 = 0x08; //使能外部中断0,使能多功能中断0(其中包括TM0定时)
_intc1 = 0x01; //使能多功能中断1(即使能TM1中断)
_intc2 = 0x00; //禁止其它中断
_mfi0 = 0x02; //TM0比较匹配A中断使能
_mfi1 = 0x02; //TM1比较匹配A中断使能
_mfi2 = 0x00; //禁止其它中断
_emi = 1; //开总中断
_t0on = 1; //启动定时器0
_t1on = 1; //启动定时器1
_int0e = 1; //使能外部中断0
通过禁止相关中断使能位,可以屏蔽中断请求,然而,一旦中断请求标志位被设定,它们会被保留在中断控制寄存器内,直到相应的中断服务子程序执行或请求标志位被软件指令清除。
多功能中断中所含中断相应程序执行时,多功能中断请求标志MF0F-MF2F 可以自动清零,但各自的请求标志需在应用程序中手动清除。
如下图展示的是HT66F018的中断结构图,可以在datasheet的Page117中找到,在编写中断函数时,主要需要用到下图中的*Vector(中断向量)*一列。各个中断使能位以及相应的请求标志位,以优先级的次序显示在下图。一些中断源有自己的向量,但是有些中断却共用多功能中断向量。
/* timer0 interrupt, 1ms */
void __attribute((interrupt(0x0C))) timer0(void)
{
_t0af = 0; //清除T0中断标志位
//user code start
//...
//user code end
/* 一旦中断子程序被响应,系统将自动清除EMI位,所有其它的中断将被屏蔽 */
_emi = 1; //手动打开总中断
}
/* timer1 interrupt, 200us */
void __attribute((interrupt(0x10))) timer1(void)
{
_t1af = 0;
//user code start
//...
//user code end
/* 一旦中断子程序被响应,系统将自动清除EMI位,所有其它的中断将被屏蔽 */
_emi = 1; //手动打开总中断
}
/* int0 *、
void __attribute((interrupt(0x04))) Int0(void)
{
//不需要清除中断标志位
_emi = 1; //手动打开总中断
}
一旦中断子程序被响应,系统将自动清除EMI位,所有其它的中断将被屏蔽,这个方式可以防止任何进一步的中断嵌套。其它中断请求可能发生在此期间,虽然中断不会立即响应,但是中断请求标志位会被记录。
HT66F018包含一个多通道的A/D转换器,它们可以直接接入外部模拟信号(来自传感器或其它控制信号)并直接将这些信号转换成12位的数字量。
转换流程如下:ADCR0 寄存器中的START 位,用于打开和复位A/D 转换器。当单片机设定此位从逻辑低到逻辑高,然后再到逻辑低,就会开始一个模数转换周期。当START 位从逻辑低到逻辑高,但不再回到逻辑低时,ADCR0 寄存器中的EOCB 位置“1”,复位模数转换器。START 位用于控制内部模数换转器的开启动作。ADCR0 寄存器中的EOCB 位用于表明模数转换过程的完成。在转换周期结束后,EOCB 位会被单片机自动地置为“0”。
代码描述:
void adc_init()
{
_adcr0 = 0x00;
_adrfs = 0; //ADC 数据高字节是ADRH 的bit 3~bit 0,低字节是ADRL 的bit 7~bit 0
_adcr1 = 0x03; //设置AD参考为内部ADC电源,确定时钟为系统时钟8分频,即AD时钟周期为1us.
//AD转换时间为16个AD时钟周期。
_acerl = 0x26; //选择PA6/pb2/pb1为AD输入引脚(AN5/AN2/AN1)
}
/* 根据通道值获取ADC采样值 */
uint16_t GetAdResult(uint8_t adc_chan)
{
uint16_t result;
_adcr0 = adc_chan;
_start = 0;
_start = 1;
_start = 0;
while(_eocb);
//_adrfs为0,使用下面数据格式拼接处结果
result = (_adrh << 4) & 0xFF0;
result = result | ((_adrl >> 4) & 0xF);
return result;
}
HT66F018的编码总体来说还是比较简单的,只是存在不少的坑,比如中断服务中单片机会自动清除emi,这种情况我还是第一回碰到。最后要说的是,多读几遍datasheet是关键,很多编程的关键点在datasheet中都有说明;中文的datasheet,理解起来也比较快。