1.1 整体框架介绍
本次提供以下模块的Demo程序:

图1-1
整个工程包含3个文件夹,如下所示:

Source包含.c文件,如下所示:

每个模块包含两个.c文件,一个命名为xxx..c,一个命名为xxx_Test.c;第一个c文件包含了模块相关的配置程序,第二个c文件包含了模块相关的测试程序;
Include中存放各个模块的头文件及系统头文件。
1.2使用实例说明
在Keil中选择包含相应模块程序的工程序进行编译加载,对于有些模块,因为具有多个工作方式,为了测试不同工作方式下的功能,可在相应模块的.h文件中打开相应的宏定义,再进行编译加载;例如,需要测试Timer2工作在方式0捕捉模式的功能,可按如下步骤进行测试:
- 在工程下拉菜单中选择Timer2工程(如图1-2所示);

图1-2
选择之后,包含Timer2模块程序的工程被打开,如下图所示:

图1-3
.c文件中带“”,表示该文件包含在当前工程中,否则不包含在当前工程中。
- 在相应的Timer.h头文件中打开宏定义“#define MODE0”(如图1-4所示);

图1-4
2.1.1工作方式配置介绍
系统时钟可配置为低频、高频,PLL高频3种模式,sysclk_define.h文件包含以下几个宏定义,分别用于初始化时钟在相应的模式:
#define LOW_FREQUENCE:执行函数void SetClk()可将系统时钟配置为低频模式; #define HIGH_FREQUENCE:执行函数void SetClk()可将系统时钟配置为高频模式; #define PLL_HIGH_FREQUENCE:执行函数void SetClk()可将系统时钟配置为高频
PLL模式;
将相应功能的宏定义打开,屏蔽其他宏定义,编译、加载运行可进行测试。
2.1.2测试程序介绍
选择“Sysclk”工程,打开宏定义“#define LOW_FREQUENCE”,其它宏定义都屏蔽,设置系统时钟为低频时钟,Option中选择内建128KHz RC振荡时钟作为OSC1CLK;编译、加载运行,测试P0.0口可得到以下9.1KHz波形:

图2-1
由于c程序中IO翻转一次需要7个时钟周期,所以IO翻转产生的方波频率应为:
f=128KHz/(7*2)=9.1KHz
注:如果不能观察到上述结果,则检查option是否配置正确;
2.1.3寄存器简要介绍
CLKCON
| | |
| 32K_SPDUP | 32.768KHz振荡器加速模式控制位 0:32.768kHz振荡器常规模式, 由软件清除 1:32.768kHz加速模式,由软件或者硬件置起 详细说明见Spec |
| | 系统时钟预分频器 00:fSYS = fOSC 01:fSYS = fOSC / 2 10:fSYS = fOSC / 4 11:fSYS = fOSC / 12 如果选择OSC1CLK为SYSCLK时钟源,则fSYS = fOSC1,与CLKS[1:0]内容无关。 |
| | OSC2CLK开关控制寄存器 0:关闭OSC2CLK 1:打开OSC2CLK |
| | 频率选择位 0:选择OSC1CLK为SYSCLK 1:选择OSCSCLK为SYSCLK |
PLLCON
| | |
| | PLL状态位 0:锁相环没有锁住相位 1:锁相环锁住相位 锁相环锁住相位后可以输出稳定的时钟 |
| | PLL开关控制位 0:PLL关闭 1:PLL开启 PLL开启必须OSC2ON=1时才有效 |
| | PLL系统时钟源控制位 0:PLL不作为OSCSCLK 1:PLL的二分频作为OSCSCLK PLL的输入时钟必须大于5M |
相关内部RC校正寄存器CLKLO、CLKRC0、CLKRC1的详细说明见Spec。
SH88F6161提供61个位可编程双向I/O端口,端口数据在寄存器Px中,端口控制寄存器PxCRy控制端口是作为输入或者输出。当端口作为输入时,每个I/O端口带有由PxPCRy控制的内部上拉电阻。
demo程序中函数void Sysclk_Test(),以IO翻转为例给出了IO的配置使用方法;
SH88F6161有定时器2和定时器3两个定时器,定时器2可配置为16位捕获、16位自动重载、可编程时钟输出三种方式;定时器3只可配置为16位自动重载方式。
demo程序以Timer2为例给出了不同工作模式的配置方法。
2.3.1工作方式配置介绍
timer_define.h文件中包含以下几个宏:
#define MODE0:设置Timer2工作在16位捕获方式(下降沿捕获)
#define MODE1:设置Timer2工作在16位重载方式
#define MODE2:设置Timer2工作在可编程时钟输出方式
将相应功能的宏定义打开,屏蔽其他宏定义,编译、加载运行可进行测试。
2.3.2测试程序介绍
选择“Timer2”工程,依次在timer_define.h文件中打开相应宏,然后进行编译加载全速运行,观察现象
- 当打开宏“#define MODE0”,全速运行后,T2EX引脚输入下降沿会产生一次捕获,并产生外部事件捕获中断;
- 当打开宏“#define MODE1”,全速运行后,定时器工作在16位自动重载方式,定时产生溢出中断;
- 当打开宏“#define MODE2”,全速运行后,定时器工作在可编程时钟输出方式,产生如下31.9KHz波形(系统时钟为128KHz);

图2-2
输出时钟频率计算公式:
、
2.3.3相关寄存器介绍
RCAP2L,RCAP2H,TL2,TH2
位编号 | 位符号 | 说明 |
7-0 | RCAP2L [7:0] | 定时器2重载/捕获数据 |
RCAP2H [7:0] |
7-0 | TL2 [7:0] | 定时器2高位低位计数器 |
TH2 [7:0] |
T2CON
位编号 | 位符号 | 说明 |
7 | TF2 | 定时器2溢出标志位 0:无溢出(必须由软件清0) 1:溢出(由硬件设1) |
6 | EXF2 | T2EX引脚外部事件输入(下降沿)被检测到的标志位 0:无外部事件输入(必须由软件清0) 1:检测到外部输入(如果EXEN2 = 1,由硬件设1) |
3 | EXEN2 | T2EX引脚上的外部事件输入(下降沿)用作重载/捕获触发器允许/禁止控制位 0:忽略T2EX引脚上的事件 1:检测到T2EX 引脚上一个下降沿,产生一个捕获或重载 |
2 | TR2 | 定时器2开始/停止控制位 0:停止定时器2 1:开始定时器2 |
1 | C/ | 定时器2定时器/计数器方式选定位 0:定时器方式,T2引脚用作I/O端口 1:计数器方式,内部上拉电阻被打开 |
0 | CP/ | 捕获/重载方式选定位 0:16位带重载功能的定时器/计数器 1:16位带捕获功能的定时器/计数器 |
T2MOD
位编号 | 位符号 | 说明 |
7 | TCLKP2 | 分频选择控制位 0:选择系统时钟的1/12作为定时器2的时钟源 1:系统时钟作为定时器2的时钟源 |
1 | T2OE | 定时器2输出允许位 0:设置P2.4/T2作为时钟输入或I/O端口 1:设置P2.4/T2作为时钟输出 |
0 | DCEN | 递减计数允许位 0:禁止定时器2作为递增/递减计数器,定时器2仅作为递增计数器 1:允许定时器2作为递增/递减计数器 |
SH88F6161具有四个可编程计数器,分别为PCA0、PCA1、PCA2、PCA3;
demo程序以PCA0为例,给出了其比较/捕捉模块分别工作于Mode0~Mode3时的参考程序。
2.4.1工作方式配置介绍
pca_define.h文件中包含以下几个宏:
#define MODE0:配置比较/捕捉模块0工作在边沿触发模式
#define MODE1:配置比较/捕捉模块0工作在软件定时方式
#define MODE2: 配置比较/捕捉模块0工作在频率输出方式
#define MODE3_PWM8:配置比较/捕捉模块0工作在8位脉宽调制
#define MODE3_PWM16:配置比较/捕捉模块0工作在16位脉宽调制
#define MODE3_XPWM16:配置比较/捕捉模块0工作在16位相位修正脉宽调制
#define MODE3_XPPWM16:配置比较/捕捉模块0工作在16位相频修正脉宽调制
将相应功能的宏定义打开,屏蔽其他宏定义,编译、加载运行可进行测试。
2.4.2测试程序介绍
选择“PCA”工程,依次在pca_define.h文件中打开相应宏,然后进行编译加载全速运行,观察现象;
1. 打开宏“#define MODE0”,屏蔽其他宏定义,编译加载后,全速运行,P0CEX0引脚上升沿/下降沿会触发一次捕捉,并产生相应中断;
2. 打开宏“#define MODE1”,屏蔽其他宏定义,编译加载后,全速运行,可以实现连续软件定时,当PCA0计数值与P0CPH0和P0CPL0中的值匹配时产生一次中断,同时P0CEX0口翻转一次;(PxTOP,PxCPn可变)
3. 打开宏“#define MODE2”,屏蔽其他宏定义,编译加载后,全速运行,P0CEX0引脚可输出如下波形(3.965KHz):

图2-3
FPxCEXn= FPCAx /(2 × PxCPHn)
如果应用中需要改变波形占空比和频率,则可通过适时地改变PxCPHn来获得相应的波形;PxTOPL固定为0xFF,用户可以配置PxTOPH来改变计数最大值;
4. 打开宏“#define MODE3_PWM8”,屏蔽其他宏定义,编译加载后,全速运行,P0CEX0输出占空比为0.8的正向波形,P0CEX1输出占空比为0.8的反向波形,如下图所示:

图2-4
Duty=(256-(PxCPHn+1))/256
如果应用中需要Duty可变的PWM波形,则可通过适时的改变PxCPHn来获取希望波形;
PxTOPL不可改变;
5. 打开宏“#define MODE3_PWM16”,屏蔽其他宏定义,编译加载后,全速运行,P0CEX0输出占空比为0.8的正向波形,P0CEX1输出占空比为0.8的反向波形,如下图所示:

图2-5
Duty=(65536-(PxCPn+1))/65536
如果应用中需要Duty可变的PWM波形,则可通过适时的改变PxCPn(PxCPHn,PxCPLn)和PxTOP来获取希望波形;
6. 打开宏“#define MODE3_XPWM16”,屏蔽其他宏定义,编译加载后,全速运行,P0CEX0输出频率为250Hz的正向波形,P0CEX1输出频率为250Hz的反向波形,如下图所示:

图2-6
如果应用中需要频率和占空比可变的波形,则可通过适时的改变PxTOP和PxCPn(PxCPHn,PxCPLn)来获取相应波形;在一个定时器时钟周期里PCAx值等于PxTOP值,然后在下一次计数到来时PxTOP和PxCPn将得到更新。
7. 打开宏“#define MODE3_XPPWM16”,屏蔽其他宏定义,编译加载后,全速运行,P0CEX0输出频率为250Hz的正向波形,P0CEX1输出频率为250Hz的反向波形,如下图所示:

图2-7
如果应用中需要频率和占空比可变的波形,则可通过适时的改变PxTOP和PxCPn(PxCPHn,PxCPLn)来获取相应波形;PxCPn和PxTOP在0x0000点更新。
注:对于XPWM和XPPWM工作方式,一定要配置相应的PCAx工作在双沿模式,否则相应口将不能正常输出波形;
Demo程序给出了LCD的使用实例,以4COM,2SEG为例,用户可根据实际需要选择合适COM数和SEG数做相应的IO配置;配置参考void init_lcd()。
选择“Lcd”工程,编译加载运行,观察SEG1、SEG2、COM1~COM4口波形;
Demo程序给出了LED的使用实例,以2COM,8SEG为例,用户可根据实际需要选择合适COM数和SEG数做相应的IO配置;配置参考void init_led()。
选择“Led”工程,编译加载运行,观察COM1、COM2、SEG1~ SEG8口波形;
2.5.1寄存器简要介绍
DISPCON
位编号 | 位符号 | 说明 |
7 | DISPSEL | LCD,LED选择控制位 0:选择LCD驱动器,LED驱动器无效 1:选择LED驱动器,LCD驱动器无效 |
6 | DISPON | LCD使能控制位 0:禁止LCD驱动器 1:允许LCD驱动器 |
5-4 | DUTY[1:0] | LCD占空比选择位 00:1/4占空比,1/3偏置 01:1/5占空比,1/3偏置 1X:1/6占空比,1/3偏置 |
3-0 | VOL[3:0] | LCD对比度控制位 0000:VLCD = 0.531VDD 0001:VLCD = 0.563VDD 0010:VLCD = 0.594VDD 0011:VLCD = 0.625VDD 0100:VLCD = 0.656VDD 0101:VLCD = 0.688VDD 0110:VLCD = 0.719VDD 0111:VLCD = 0.750VDD 1000:VLCD = 0.781VDD 1001:VLCD = 0.813VDD 1010:VLCD = 0.844VDD 1011:VLCD = 0.875VDD 1100:VLCD = 0.906VDD 1101:VLCD = 0.938VDD 1110:VLCD = 0.969VDD 1111:VLCD = 1.000VDD |
DISPCON1
位编号 | 位符号 | 说明 |
4 | RLCD | LCD偏置电阻选择控制位 0:LCD偏置电阻为225k 1:LCD偏置电阻总和为900k |
3-2 | FCCTL[1:0] | 充电时间控制位 00:1/8 LCD com周期 01:1/16 LCD com周期 10:1/32 LCD com周期 11:1/64 LCD com周期 充电时间控制位仅在快速充电模式下有效 |
1-0 | MOD[1:0] | 驱动模式选择位 00:传统电阻型模式,偏置电阻总和为225k/900k 01:传统电阻型模式,偏置电阻总和为60k 1X:快速充电模式,偏置电阻总和自动在60k和225k/900k之间切换 |
其它相关寄存器详见Spec。
TWI串行总线采用两根线(SDA和SCL)在总线和装置之间传递信息。SH88F6161完全符合TWI总线规范,自动对字节进行传输进行处理,并对串行通讯进行跟踪。
2.6.1工作方式配置介绍
twi_define.h文件中定义了以下几个模式:
#define MT_MODE:打开该宏,配置6161工作在主机传送模式;
#define MR_MODE:打开该宏,配置6161工作在主机接收模式;
#defineSLAVE_MODE:打开该宏,配置6161工作在从机模式;
将相应功能的宏定义打开,屏蔽其他宏定义,编译、加载运行可进行测试。
2.6.2测试程序介绍
Twi_Test.c分别以作为主机和从机传送和接收10个byte数据为例给出了该模块的应用;
1. 选择“Twi”工程后,打开宏定义“MT_MODE”,编译、加载运行可测试6161作为主机向从机传送数据,分别为“0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A……..”
2. 选择“Twi”工程后,打开宏定义“MR_MODE”,编译、加载运行可测试6161作为主机从从机接收10个byte数据;
3. 选择“Twi”工程后,打开宏定义“SLAVE_MODE”,编译、加载运行可测试6161作为从机:
- 向主机发送10个byte数据,分别为“0x40, 0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49”
- 从主机接收10个byte数据,分别为“0x40, 0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49”
本模块测试需要两个6161板子,一个作为主机,一个作为从机进行配合。
注:如果不能得到正确结果,请检查SCL和SDA是否接上拉电阻,通常选择10k
串行外部设备接口(SPI)是一种高速串行通信接口,允许MCU与外围设备(包括其它MCU)进行全双工,同步串行通讯。
2.7.1工作方式配置介绍
spi_define.h文件中定义了以下两个模式:
#define SLAVE_MODE:打开该宏,配置6161作为从机;
#define MASTER_MODE:打开该宏,配置6161作为主机;
2.7.2测试程序介绍
以6161作为主机向另一块作为从机的6161传送数据为例,具体过程如下:
主机6161向从机6161传送“0x40, 0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A”;从机收到主机发送的数据后,将相应数据返回给主机,主机接收到从机返回的数据后,将其保存到rcv_data[]数组中。
选在“Spi”工程后,打开宏定义“#define MASTER_MODE”编译,下载运行使其作为主机;
选在“Spi”工程后,打开宏定义“#define SLAVE_MODE”编译,下载运行使其作为从机;
本模块程序运行测试需要两块6161板子配合。
注:如果从机向主机返回的数据内容与期望值有差别,可尝试提高从机的的系统时钟频率,或降低主机的系统时钟频率;
本次实例中,以一个主设备一个从设备的通讯网络为例,因此无需控制SS引脚,即只需接SCK,MOSI,MISO三根信号线;
2.7.3寄存器简要介绍
SPCON
| | |
| | 传送方向选择位 0:MSB优先发送 1:LSB优先发送 |
| | SP设备选择位 0:配置SPI作为从属设备 1:配置SPI作为主设备 |
| | 时钟相位控制位 0:SCK周期的第一沿采集数据 1:SCK周期的第二沿采集数据 |
| | 时钟极性控制位 0:在Idle状态下SCK处于低电平 1:在Idle状态下SCK处于高电平 |
| | 引脚控制位 0:在主和从属模式下,打开引脚 1:在主和从属模式下,关闭引脚 如果SSDIS置1,不产生MODF中断请求。 在从属模式下,如果CPHA = 0,该位不起作用。 |
| | 串行外部设备时钟速率选择位 000: fSYS /2 001: fSYS /4 010: fSYS /8 011: fSYS /16 100: fSYS /32 101: fSYS /64 110: fSYS /128 111: fSYS /256 |
SPSTA
| | |
| | |
| | 串行外部设备数据传送标志位 0:由软件清0 1:表明已完成数据传输,由硬件置1 |
| | 模式故障位 0:由软件清0 1:表明引脚电平与SPI模式不一致,由硬件置1 |
| | 写入冲突标志位 0:有软件清0,表明已处理写入冲突 1:由硬件置1,表明检测到一个冲突 |
| | 接收超限位 0:表明已处理接收超限,由软件清0 1:表明已检测到接收超限,由硬件置1 |
SPDAT
| | |
| | 写入SPDAT的数据被放置到发送移位寄存器中。读取SPDAT时将获得接收移位换寄存器的数据。 |
Uart工作方式列表:
SM0 | | | 类型 | 波特率 | 帧长度 | 起始位 | 停止位 | 第9位 |
0 | | | 同步 | fSYS/(4或12) | 8位 | 无 | 无 | 无 |
0 | | | 异步 | 自带波特率发生器的溢出率/16 | 10位 | 1 | 1 | 无 |
1 | | | 异步 | fSYS/(32或64) | 11位 | 1 | 1 | 0,1 |
1 | | | 异步 | 自带波特率发生器的溢出率/16 | 11位 | 1 | 1 | 0,1 |
通过配置相应寄存器可使Uart工作在不同的工作方式,本次Demo程序以Uart0的方式1为例,给出了6161传送数据和接收数据的实例。
注:Uart0和Uart1完全相同;
2.8.1工作方式配置介绍
uart_define.h文件中,定义了以下两个宏:
#define Enable_uart_TX_test:测试6161工作在方式1传送数据;
#define Enable_uart_RX_test:测试6161工作在方式1接收数据;
2.8.2测试程序介绍
本项测试需结合串口助手调试,选择“Uart”工程后,打开宏定义“#define Enable_uart_TX_test”,编译、加载运行后,通过串口助手可看到6161连续传送0x96;
注:测试时,系统时钟选择外挂晶振8M,波特率为9600;
2.8.3寄存器介绍
PCON
位编号 | 位符号 | 说明 |
7 | SMOD | UART0/1波特率加倍器 0:在方式2中,波特率为系统时钟的1/64 1:在方式2中,波特率为系统时钟的1/32 |
6 | SSTAT | SCON[7:5]功能选择 0:SCON[7:5]工作方式作为SM0,SM1,SM2 1:SCON[7:5]工作方式作为FE,RXOV,TXCOL |
3-2 | GF[1:0] | 用于软件的通用标志位 |
1 | PD | 掉电模式控制位 |
0 | IDL | 空闲模式控制位 |
SCON
位编号 | 位符号 | 说明 |
7-6 | SM[0:1] | EUART0串行方式控制位,SSTAT = 0 00:方式0,同步方式,固定波特率 01:方式1,8位异步方式,可变波特率 10:方式2,9位异步方式,固定波特率 11:方式3,9位异步方式,可变波特率 |
7 | FE | EUART0帧出错标志位,当FE位被读时,SSTAT位必须被置位 0:无帧出错,由软件清零 1:帧出错,由硬件置位 |
6 | RXOV | EUART0接收溢出标志位,当RXOV位被读时,SSTAT 位必须被置位 0:无接收溢出,由软件清零 1:接收溢出,由硬件置位 |
5 | SM2 | EUART0多处理机通讯允许位(第9位“1”校验器),SSTAT = 0 0:在方式0下,波特率是系统时钟的1/12 在方式1下,禁止停止位确认检验,任何停止位都会置位RI 在方式2和3下,任何字节都会置位RI 1:在方式0下,波特率是系统时钟的1/4 在方式1下,允许停止位确认检验,只有有效的停止位(1)才能置位RI 在方式2和3下,只有地址字节(第9位 = 1)才能置位RI |
5 | TXCOL | EUART0发送冲突标志位,当TXCOL位被读时,SSTAT位必须被置位 0:无发送冲突,由软件清零 1:发送冲突,由硬件置位 |
4 | REN | EUART0接收器允许位 0:接收禁止 1:接收允许 |
3 | TB8 | 在EUART0的方式2和3下发送的第9位,由软件置位或清零 |
2 | RB8 | 在EUART0的方式1,2和3下接收的第9位 在方式0下,不使用RB8 在方式1下,如果接收中断发生,停止位移入RB8 在方式2和3下,接收第9位 |
1 | TI | EUART0的传送中断标志位 0:由软件清零 1:由硬件置位 |
0 | RI | EUART0的接收中断标志位 0:由软件清零 1:由硬件置位 |
SBUF
位编号 | 位符号 | 说明 |
7-0 | SBUF[7:0] | 这个寄存器寻址两个寄存器:一个移位寄存器和一个接收锁存寄存器 SBUF的写入将发送字节到移位寄存器中,然后开始传输 SBUF的读取返回接收锁存器中的内容 |
SADDR、SADEN(多机通讯时需设置)
位编号 | 位符号 | 说明 |
7-0 | SADDR[7:0] | 寄存器SADDR定义了EUART0的从机地址 |
7-0 | SADEN[7:0] | 寄存器SADEN是一个位屏蔽寄存器,决定SADDR的哪些位被检验 0:SADDR中的相应位被忽略 1:SADDR中的相应位对照接收到的地址被检验 |
SBRTH、SBRTL
位编号 | 位符号 | 说明 |
7 | SBRTEN | EUART0波特率发生器使能控制位 0:关闭(默认) 1:打开 |
6-0, 7-0 | SBRT[14:0] | EUART0波特率发生器计数器高7位和低8位寄存器 |
SFINE
位编号 | 位符号 | 说明 |
3-0 | SFINE[3:0] | EUART0波特率发生器微调数据寄存器 |
USB主机和从机之间的通信是建立在既定的USB协议基础上,需要主机驱动程序和从机驱动程序配合实现;根据不同的应用场合,用户可以编写相应的USB驱动程序实现与PC主机的通讯。
USB协议规定了USB设备和PC主机进行通讯的过程,主机和从机进行通讯的第一个阶段是枚举过程,通过枚举,从机设备会将其描述符信息发送给主机,主机会在枚举完之后根据设备的描述符信息发起后续的通信,后续通信的过程根据枚举时得到的设备配置信息的不同而不同。
2.9.1总体流程图
使用USB模块之前,首先需调用模块初始化函数void usb_init (),之后USB从机将等待主机发送命令,并产生相应中断;

图2-8
2.9.2基本通信过程说明
如果从机可以接收主机向控制端点0发送的数据,收到SETUP命令后,需进行如下操作:
- 置位OEP0RDY;
- 待产生OEP0中断后,通过OEP0CNT寄存器可获取接收到的数据个数,从EP0 OUT Buf可获取所收到的数据内容;
- 如果OEP0CNT的值小于8,则IEP0CNT清0,置位IEP0RDY,此时主机会向从机发送In包,从机将向主机传送0长度数据包,本次控制传输结束。要想开始下一笔控制传输,主机需重新发送SETUP包;
- 如果OEP0CNT的值等于8,则重复步骤1)~3);
如果从机有数据通过端点0向主机发送,收到SETUP命令后,需执行如下操作:
- 设置相应的IEP0DTG;
- 向EP0 IN BUF填写数据内容,向IEP0CNT填写数据个数;
- 置位IEP0RDY;
- 待产生IEP0中断后,如果IEP0CNT值小于8,表示从机没有剩余数据向主机发送,此时应置位OEP0RDY,等待主机向从机传送0长度数据包产生OEP0中断,本次控制传输结束;
- 如果IEP0CNT值等于8,表示从机还有数据向主机发送,此时应重复1)~4);
如果从机可以接收主机向端点1传送的数据,则需执行如下操作:
- 设置OEP1BUFSEL占用相应buf,
- 置位OEP1RDY;
- 待产生OEP1中断后,通过OEP1CNT寄存器可获取接收到的数据个数,释放当前被占用的buf,从中可获取接收到的数据内容,如果当前接收到的数据个数等于16,则重复1)~3);如果当前接收到的数据个数小于16,本次传输结束;
如果从机有数据通过端点1向主机发送,则需执行如下操作:
- 设置IEP1DTG;
- 填写IEP1CNT,填写相应的BUF,并设置IEP1BUFSEL占用BUF;
- 置位IEP1RDY,向主机发送数据;
- 产生IEP1中断后,如果从机没有数据传送(即IEP1CNT小于16),则本次数据传输结束,否则重复步骤1)~4);
如果从机可以接收主机向端点2传送的数据,则需执行如下操作:
- 设置OEP2BUFSEL占用相应buf,
- 置位OEP2RDY;
- 待产生OEP2中断后,通过OEP2CNT寄存器可获取接收到的数据个数,释放当前被占用的buf,从中可获取接收到的数据内容,如果当前接收到的数据个数等于64,则重复1)~3);如果当前接收到的数据个数小于64,本次传输结束;
如果从机有数据通过端点2向主机发送,则需执行如下操作:
- 设置IEP2DTG;
- 填写IEP2CNT,填写相应的BUF,并设置IEP2BUFSEL占用BUF;
- 置位IEP2RDY,向主机发送数据;
- 产生IEP2中断后,如果从机没有数据传送(即IEP2CNT小于64),则本次数据传输结束,否则重复步骤1)~4);
2.9.3应用实例
本次Demo程序以HID类设备为例,给出了枚举过程。

当6161下载该程序运行后,插入PC,PC端会识别到一个HID类设备插入,如下所示:

如果用户需要实现其他应用,则应根据USB协议规定修改相应的描述符信息,并增加相应的类请求响应程序以及后续通信相关程序。
ADC负责模拟信号到相应12位的数字信号的转换,支持VDD,内建1.5V,内建2.5V,外接VREF四种基准电压,可通过软件启动AD转换,也可通过触发源触发AD转换,另外通过启动比较功能,可实现连续转换。
2.10.1工作方式配置介绍
adc_define.h文件中定义了以下几个宏:
#define STARTUP_BY_SOFTWARE:打开该宏,测试软件触发一次ADC0转换
#define STARTUP_BY_HARDWARE:打开该宏,测试外部中断2上升沿触发ADC0转换
#define DIGITAL_COMPARE_FUNCTION:打开该宏,测试连续ADC0转换
2.10.2测试程序介绍
选择“Adc”工程,打开宏“#define STARTUP_BY_SOFTWARE”,编译、加载,
- ADC0通道(P0.0)外接电压源;
- 在ADC中断服务程序中设置断点,全速运行至断点处,通过寄存器ADCL和ADCH可观测外部电压转换值;
注:本项测试只完成一次AD转换,要想再进行一次AD转换,软件需再次启动AD转换。
选择“Adc”工程,打开宏“#define STARTUP_BY_HARDWARE”,编译、加载,
- ADC0通道(P0.0)外接电压源;
- 在ADC中断服务程序中设置断点,全速运行;
- 给P6.1口上升沿信号,可看到程序运行至断点处,此时通过寄存器ADCL和ADCH可观测外部电压转换值;
注:本项测试中,一次外部中断只能触发一次AD转换,要想再进行一次AD转换,需再次触发外部中断。
选择“Adc”工程,打开宏“#define DIGITAL_COMPARE_FUNCTION”,编译、加载,
- ADC0通道(P0.0)外接电压源;
- 在ADC中断服务程序中设置断点,全速运行至断点处,通过寄存器ADCL和ADCH可观测外部电压转换值;
- 调节电压后再全速运行,可看到程序再次运行至断点处,通过寄存器ADCL和ADCH可观测外部电压转换值;
- 重复步骤5),实现连续AD转换。
2.10.3寄存器简要介绍
| | |
| | |
| | AD模块使能、启动、比较使能、及转换完成中断标志、触发源使能、事件触发设置 |
| |
| | |
| |
| | |
| |
| | |
| |
| | |
| |
| |
寄存器的每一位详细介绍见Spec。
DAC支持自校准功能,在精度要求较高的情况下,需先进行自校准,然后再正常使用DAC。
2.11.1测试程序介绍
选择工程“Dac”,编译、加载运行,测量DAC输出口(P1.6)电压约为2.5V;
注:本次测试程序选择DACL执行写操作触发DAC输出更新,选择内建2.5V作为参考电压,且输入数字量为0xFFF,故转换输出电压应该为2.5V。
实际应用中,可根据需要在初始化DAC时选择其他触发方式或决定是否开启DAC补偿。
2.11.2寄存器介绍
DACCON0
| | |
| | DAC转换控制位 0: DAC 禁止 1: DAC使能 |
| | DAC输出驱动选择: 00:DAC输出不带缓冲器. 01:DAC输出带缓冲器(1倍) 1x:DAC输出带缓冲器(3倍) |
| | 锁存器触发源选择 00: DACL执行写操作触发DAC输出更新 01: 定时器2溢出触发DAC输出更新 10: 定时器3溢出触发DAC输出更新 11: PCA0定时器溢出触发DAC输出更新 |
| | |
| | DAC端口配置寄存器 0:P1.6作为为IO口 1:P1.6作为DAC输出口 |
| | DAC中断标志位 0:DAC转换未完成. 1:DAC转换完成,由硬件置1,软件清0 |
DACCON1
| | |
| | DAC自校准操作控制(当DACOSEL[1:0] = 01或1x时,自校准功能有效) 0: 自校准关闭(自校准完成,硬件清零) 1: 自校准开启(软件开启) |
| | DAC补偿开关 0: 开启DAC补偿 1: 关闭DAC补偿 |
| | 外部参考电压输入口选择 0:P1.4作为I/O口 1:P1.4作为VREF输入引脚 |
| | 内建电压选择: 0:内建2.5V 1:内建1.5V (内建电压切换需要1ms的稳定时间) |
| | 内建1.5V/2.5V开关: 0:内建1.5V/2.5V关(P1.5作为I/O口) 1:内建1.5V/2.5V开(P1.5作为内部参考电压输出引脚) (内建电压开启需要1ms的稳定时间) |
| | DAC的参考源选择: 00: 选择VDD为基准电压 01: 选择外部VREF端口输入为基准电压 1x: 选择内建电压1.5V/2.5V为基准电压 (DACSREF选择内建电压1.5V/2.5V时,确保REFON = 1,REFSEL选择需要的内建电压) |
DACCAL
| | |
| | DAC自校准补偿电压数据符号位: 0:正(转换值比实际的值大) 1:负(转换值比实际的值小) |
| | DAC自校准补偿电压数据 (DAC自校准完成,根据校准结果更新此寄存器。 当OFFSETSW = 0时,实际DAC的输出是DACH:DACL与OFFSETDATA经过运算后的输出值,以便DAC输出精度更高 当OFFSETSW = 1时,DAC的输出为DACH:DACL对应的模拟电压) |
注:该寄存器,在执行DAC自校准功能时,硬件会自动更新;另外,软件也可修改该寄存器,如,通常为了提高精度,软件会对多次自校准后得到的DACCAL值求平均,然后再将其写入DACCAL。
DACH、DACL
| | |
| | DAC数据 位3~0是12位DAC数据字的高4位。 位7~0是12位DAC数据字的低8位。 |
本次Demo程序给出了读写EEPROM的接口函数,如下:
1)UINT8 EEPromByteRead(UINT8 nAddrH,UINT8 nAddrL)
从EEPROM指定地址处读取1个byte;
2)void EEPromByteProgram(UINT8 nAddrH,UINT8 nAddrL, UINT8 nData)
向EEPROM指定地址处写一个byte;
3)void EEPromSectorErase(UINT8 nAddrH)
擦除EEPROM指定扇区中内容;
注:在对EEPROM进行擦除和写操作之前,一定要关闭中断,待操作结束后,才可打开中断;另外,对Flash的读、写、擦除操作过程类似于类EEPROM操作,唯一区别是,在擦除或写、读之前应将FAC位清0。