Bootstrap

单片机STC8H入门

目录

概述

  STC8H系列单片机是不需要外部晶振和外部复位的单片机。在相同的工作频率下,STC8H系列单片机比传统的8051快约12倍,是宽电压/高速/高可靠/低功耗/强抗静电/较强干扰的新一代8051单片机。


一、开发环境搭建

1.1 keil的安装

  1. 用常用的C51版的keil安装,可以进入下面链接下载:
    https://download.csdn.net/download/weixin_44567668/85561379
  2. 此时缺少STC8的芯片库,打开stc-isp-15xx-v6.87H,选择keil仿真,添加头文件即可,isp可以根据下面链接下载:
    https://download.csdn.net/download/weixin_44567668/87430182

1.2 keil工程的创建

  1. 首先新建Project文件夹里面包含以下文件
    在这里插入图片描述

CORE:包含51的官方interrupt.asm和STARTUP.A51
BSP:主要包含驱动文件,如GPIO、uart
APP:目前只存放main.c和stc8hxx_it.c中断文件
OBJ:存放编译生成文件
Header:存放全部.h格式头文件

  1. keil创建工程
    ①打开keil选择Project–New…,选择上面新建的文件夹,文件名为test请添加图片描述
    ②选择芯片型号,点击OK请添加图片描述

  2. 右击Target 1,选择Mange Project …
    在这里插入图片描述
    ①创建以下文件
    在这里插入图片描述
    ②右击具体文件,依次将文件夹文件添加进来
    请添加图片描述
    在这里插入图片描述

  3. 选择Options For Target
    请添加图片描述
    ①将Output和Listing的生成文件夹变成OBJ
    请添加图片描述
    ②将Target–Memory Model设置成Large
    在这里插入图片描述
    ③在C51–include Paths添加头文件路径,记得将其修改成相对路径
    在这里插入图片描述

二、STC基础

2.1寄存器sfr和sbit介绍

"sfr"指令:用来直接描述硬件地址。小白先解成一组IO口的起始地址中数据 sfr P0 = 0x80; P0=0;//也就是对P0口全部给0
"sbit"指令:对应可位导址空间的一个位,小白先理解成"一个IO口/针脚"的地址中的数据。

sfr   P0   =  0x80;
sbit  P00  =  P0^0;

注意:实际上了解一下就好,一般封装在官方头文件stc8h.h中

2.2 ISP下载程序

这个最好直接问公司前辈,因为下载方式不唯一,而且问人比较快

2.3 存储器简介

  STC8H系列单片机的程序存储器和数据存储器各自独立编址的。

  单片机复位后,程序计数器(PC)的内容为00001,从 0000H 单元开始执行程序。另外中断服务程序的入口地址(又称中断向量)也位于程序存储器单元。
  在程序存储器中,每个中断都有一个固定的入口地址,当中断发生并得到响应后,单片机就会自动跳转到相应的中断入口地址去执行程序。外部中断0(INT0)的中断服务程序的入口地址是0003H,定时器/计数器0(TIMER0)中断服务程序的入口地址是 000BH,外部中断1(TNT1)的中断服务程序的入口地址是0013H,定时器/计数器|(TIMERI)的中断服务程序的入口地址是001BH等。

  其内部集成大容量的数据存储器,有两个地址空间:内部RAM(256字节)和内部扩展RAM
  内部RAM共256字节,可分为2个部分:低128字节RAM和高128字节RAM。低128字节的数据存储器与传统8051兼容,既可直接寻址也可间接寻址。高128字节RAM(在8052中扩展了高128字节RAM)与特殊功能寄存器区共用相同的逻辑地址,都使用8OH~FFH,但在物理上是分别独立的,使用时通过不同的寻址方式加以区分。高128字节RAM只能间接寻址,特殊功能寄存器区只可直接寻址。
  低128字节RAM 也称通用 RAM 区。通用RAM 区又可分为工作寄存器组区,可位寻址区,用户RAM区和堆栈区。工作寄存器组区地址从00H ~ 1FH共32字节单元,分为4组,每一组称为一个寄存器组,每组包含8个8位的工作寄存器,编号均为RO ~ R7,但属于不同的物理空间。通过使用工作寄存器组,可以提高运算速度。RO ~ R7是常用的寄存器,提供4组是因为1组往往不够用。程序状态字PSW寄存器中的RS1和RSO组合决定当前使用的工作寄存器组,见下面PSW寄存器的介绍。

三、I/O口

3.1 端口数据寄存器(Px)

写0:输出低电平到端口缓冲区
写1:输出高电平到端口缓冲区
读:直接读端口管脚上的电平

在这里插入图片描述

3.2 端口模式配置寄存器(PxM0,PxM1)

在这里插入图片描述
配置端口模式
在这里插入图片描述
注意
①当有I/O口被选择为ADC输入通道时,必须设置PxM0/PxM1寄存器将I/O口模式设置成输入模式。另外如果MCU进入掉电模式/时钟停振模式后,仍需使能ADC通道,则需要设置PxIE寄存器关闭数字输入,才能保证不会有额外的耗电
②虽然每个I/O口在弱上拉(准双向口)/强推挽输出/开漏模式时都能承受20mA的灌电流(还是要加限流电阻),但整个芯片的工作电流推荐不要超过70mA

3.3 端口上拉电阻控制寄存器(PxPU)

0:禁止端口内部的4.1K上拉电阻
1:使能端口内部的4.1K上拉电阻

在这里插入图片描述

3.4 示例代码

void GPIO_Init(void)
{
	P10 = 1;
	P11 = 1;
	P0M0 = 0x00;	//设置P0.9~P0.7为双向口模式
	P0M1 = 0x00; 	
	P1M0 = 0xff; 	//设置P1.1~P1.7为推挽输出模式
	P1M1 = 0x00;
	P2M0 = 0x00;	//设置P2.0~P2.7为高阻输入模式
	P2M1 = 0xff;
	P3M0 = 0xff;	//设置P3.0~P3.7为开漏模式
	P3M1 = 0xff;
	P1PU |= 0x03;	//bBit(0) | bBit(1);即使能1.1和1.0内部上拉电阻
/****************I/O读写模式*********************/
	P10 = 1;		//P1.0口输出高电平
	P10 = 0;		//P1.0口输出低电平
	
	P10 = 1;		//读取端口前先使能内部弱上拉电阻
	//当使用_nop_()函数(可理解为软件延时)时,必须在开头添加头文件#include<intrins.h>。
	//_nop_()函数相当于一个空操作(可以理解为NOP空操作指令),而_nop_()函数的空操作产生的时间与晶振有关:大概1个时钟周期
	_nop_();	
	CY = P00;		//读取端口状态	
}

四、定时器

4.1 STC8H定时器简介

  STC8H1K08有3个定时器,定时器/计数器0有4种工作模式:模式0(16位自动重装载模式),模式1(16位不可重装载模式),模式2(8位自动重装模式),模式3(不可屏蔽中断的16位自动重装载模式)。
  定时器/计数器1除模式3外,其他工作模式与定时器/计数器0相同。T1 在模式3时无效,停止计数。
  定时器T2的工作模式固定为16位自动重装载模式。T2可以当定时器使用,也可以当串口的波特率发生器和可编程时钟输出。

4.2 定时器0/1寄存器

  主要以定时器0为主

4.2.1 定时器0/1控制寄存器(TCON)

在这里插入图片描述

TF1:T1溢出中断标志。T1被允许计数以后,从初值开始加1计数。当产生溢出时由硬件将TF1位置“1”,并向CPU请求中断,一直保持到CPU响应中断时,才由硬件清“0”(也可由查询软件清“0”)。
TR1:定时器T1的运行控制位。该位由软件置位和清零。当GATE(TMOD.7)=0,TR1=1时就允许T1开始计数,TR1-0时禁止T1计数。当GATE(TMOD.7)=1,TR1=1且INT1输入高电平时,才允许T1计数。
TF0:TO溢出中断标志。TO被允许计数以后,从初值开始加1计数,当产生溢出时,由硬件置“1”TFO,向CPU请求中断,一直保持CPU响应该中断时,才由硬件清0(也可由查询软件清0)。
TR0:定时器T0的运行控制位。该位由软件置位和清零。当GATE(TMOD.3)-0,TRO=1时就允许T0开始计数,TR0-0时禁止T0计数。当GATE(TMOD.3)=1,TRO=1且INT0输入高电平时,才允许TO计数,TRO-0时禁止T0计数。
IE1:外部中断1请求源(DNT1/P3.3)标志。IE1=1,外部中断向CPU请求中断,当CPU响应该中断时由硬件清“0”IE1。
IT1:外部中断源1触发控制位。IT1=0,上升沿或下降沿均可触发外部中断1。IT1=1,外部中断1程控为下降沿触发方式。
IE0:外部中断0请求源(INTO/P3.2)标志。IE0=1外部中断0向CPU请求中断,当CPU响应外部中断时,由硬件清“0”IE0(边沿触发方式)。
IT0:外部中断源0触发控制位。IT0-0,上升沿或下降沿均可触发外部中断0。ITO=1,外部中断0程控为下降沿触发方式。

4.2.2 定时器0/1模式寄存器(TMOD)

在这里插入图片描述

T1_GATE:控制定时器1,置1时只有在INT1脚为高及TR1控制位置1时才可打开定时器/计数器1。
T0_GATE:控制定时器0,置1时只有在INT0脚为高及TR0控制位置1时才可打开定时器/计数器0。
T1_C/T:控制定时器1用作定时器或计数器,清0则用作定时器(对内部系统时钟进行计数),置1用作计数器(对引脚T1/P3.5外部脉冲进行计数)
T0_C/T:控制定时器0用作定时器或计数器,清0则用作定时器(对内部系统时钟进行计数),置1用作计数器(对引脚T0/P3.4外部脉冲进行计数)。
T1_MI/T1_M0:定时器定时器/计数器1模式选择

定时器/计数器0模式选择

T0_M1T0_M0定时器/计数器工作模式
0016位自动重载模式
0116位不自动重载模式
108位自动重载模式
11不可屏蔽中断的16位自动重载模式

注意:自动重载模式在计数器值溢出后,系统会将内部重载寄存器的值装进去;不自动重载会从0开始计数

4.2.3 定时器0模式0具体配置

(1)当GATE=0(TMOD.3)时,如TRO-1,则定时器计数。GATE=1 时,允许由外部输入INTO控制定时器0,这样可实现脉宽测量。TRO为TCON 寄存器内的控制位,TCON寄存器各位的具体功能描述见上节TCON寄存器的介绍。
(2)当CT-0时,多路开关连接到系统时钟的分频输出,To对内部系统时钟计数,TO 工作在定时方式。当c/T=1 时,多路开关连接到外部脉冲输入P3.4/T0,即TO工作在计数方式。
(3)STC 单片机的定时器 0 有两种计数速率:一种是 12T模式,每 12个时钟加 1,与传统 8051 单片机相同;另外一种是1T模式,每个时钟加1,速度是传统8051 单片机的12 倍。TO的速率由特殊功能寄存器 AUXR中的TOx12 决定,如果TOx12-0,TO则工作在12T模式;如果 TOx12=1,TO 则工作在1T模式
(4)定时器0有两个隐藏的寄存器 RL_THO 和 RL_TLO。RL_THO 与THO 共有同一个地址,RL_TLO与 TLO共有同一个地址。当TRO-0即定时器/计数器0被禁止工作时,对TLO写入的内容会同时写入RL_TLO,对THO 写入的内容也会同时写入 RL_THO。当 TRO=1 即定时器/计数器 0被允许工作少,对TL0写入内容,实际上不是写入当前寄存器TLO中,而是写入隐藏的寄存器 RL_TLO中,对THO写入内容,实际上也不是写入当前寄存器 THO 中,而是写入隐藏的寄存器 RL_THO,这样可以巧妙地实现16位重装载定时器。当读 THO和TLO的内容时,所读的内容就是THO和TL0的内容,而不是RL_THO和 RL_TLO的内容。
(5)当定时器0工作在模式 0(TMOD[1:0]/[M1,MO]=00B)时,[THO,TLO]的溢出不仅置位TFO,而且会自动将[RL_THO,RL_TLO]的内容重新装入[THO,TLO]。
(6)当TOCLKO/INT_CLKO.0=1 时,P3.5/T1管脚配置为定时器0的时钟输出 TOCLKO。输出时钟频率为T0溢出率/2。

4.2.4 定时器0计数寄存器(TL0,TH0)

在这里插入图片描述

当定时器/计数器0工作在16位模式时,TL0和TH0组合成一个16位寄存器,TL0为低字节,TH0为高字节。

4.2.5 辅助寄存器1(AUXR)

符号地址B7B6B5B4B3B2B1B0
AUXR8EHT0x12T1x12UART_M0x6T2RT2_C/TT2x12EXTRAMS1ST2

T0x12(地址B7,即最高位):定时器0速度控制位
  0:12T模式,即CPU时钟12分频
  1:1T模式,即CPU时钟不分频

4.2.6 中断与时钟输出控制寄存器(INTCLKO)

在这里插入图片描述

T0CLKO:定时器0时钟输出控制
  0:关闭时钟输出
  1:使能P3.5口的是定时器0时钟输出功能。当定时器0计数发生溢出时,P3.5口的电平自动发生翻转

4.3 定时器0计算公式

在这里插入图片描述

4.4 定时器中断系统

4.4.1 中断向量表

void TM0_Rountine(void) interrupt 1;

在这里插入图片描述

4.2.2 中断相关寄存器

(1)中断使能寄存器
在这里插入图片描述

EA:总中断允许控制位。EA的作用是使中断允许形成多级控制。即各中断源首先受EA控制:其次还受各中断源自己的中断允许控制位控制。
  0:CPU屏蔽所有的中断申请
  1:CPU开放中断
ELVD:低压检测中断允许位。
  0:禁止低压检测中断
  1:允许低压检测中断
EADC:AD转换中断允许位。
  0:禁止AD转换中断
  1:允许AD转换中断
ES:串行口1中断允许位。
  0:禁止串行口1中断
  1:允许串行口1中断
ET1:定时/计数器T1的溢出中断允许位。
  0:禁止T1中断
  1:允许T1中断
EX1:外部中断1中断允许位。
  0:禁止NT1中断
  1:允许NT1中断
ET0:定时/计数器T0的溢出中断允许位。
  0:禁止T0中断
  1:允许T0中断

EX0:外部中断0中断允许位。
  0:禁止NT0中断
  1:允许NT0中断

(2)定时器控制寄存器
在这里插入图片描述

TF1:定时器1溢出中断标志。中断服务程序中,硬件自动清零。TF0:定时器0溢出中断标志。中断服务程序中,硬件自动清零。IE1:外部中断1中断请求标志。中断服务程序中,硬件自动清零
IE0:外部中断0中断请求标志。中断服务程序中,硬件自动清零

(3)中断标志辅助寄存器
在这里插入图片描述

INT4IF:外部中断4中断请求标志。中断服务程序中硬件自动清零INT3IF:外部中断3中断请求标志。中断服务程序中硬件自动清零INT2IF:外部中断2中断请求标志。中断服务程序中硬件自动清零
T4F:定时器4溢出中断标志。中断服务程序中硬件自动清零(注意:此位为只写寄存器,不可读)。
T3IF:定时器3溢出中断标志。中断服务程序中硬件自动清零(注意:此位为只写寄存器,不可读)
T2IF:定时器2溢出中断标志。中断服务程序中硬件自动清零(注意:此位为只写寄存器,不可读)。

4.5 示范代码

//定时器配置
void Timer0Init(void)		//默认时钟24MHz
{
	AUXR |= 0x80;		//设置定时器为IT模式
	TMOD |= 0x00;		//设置成模式0
	TL0 = 0x9A;			//设置初始值
	TH0 = 0xA9;			//@(65536-[TH0,TL0])/sysclk,即多少分频
	TF0 = 0;			//清除TF0标志
	TR0 = 1;			//定时器0开始计时
	ET0 = 1;			//使能定时器中断

	EA = 1//开启全局中断
}
//定时器中断函数,用来处理事件
void TIM0_ISR(void) interrupt 1
{
	
	if((TCON & 0x20) != 0)		//清TIM0溢出中断标志
	{
		TCON &= ~0x20;
	}
	
	if(my_Timer.U16_Timer_Power_On > 0)
		my_Timer.U16_Timer_Power_On-- ;
}

五、串口通信

5.1 串口简介

  STC8H系列单片机具有4个全双工异步串行通信接口。每个串行口由2个数据缓冲器、一个移位寄存器、一个串行控制寄存器和一个波特率发生器等组成。每个串行口的数据缓冲器由2个互相独立的接收、发送缓冲器构成,可以同时发送和接收数据。
  STC8系列单片机的串口1有4种工作方式,其中两种方式的波特率是可变的,另两种是固定的,以供不同应用场合选用。串口2/串口3/串口4都只有两种工作方式,这两种方式的波特率都是可变的。用户可用软件设置不同的波特率和选择不同的工作方式。主机可通过查询或中断方式对接收/发送进行程序处理,使用十分灵活。
  其相关寄存器如下:
在这里插入图片描述

5.2 串口相关寄存器(uart2)

5.2.1 串口2控制寄存器(S2COM)

在这里插入图片描述
S2SM0:指定串口2工作模式
在这里插入图片描述

S2SM2:允许串口2在模式1时允许多机通信控制位。在模式1时,如果S2SM2位为1且S2REN位为1,则接收机处于地址帧筛选状态。此时可以利用接收到的第9位(即S2RB8)来筛选地址帧:①若 S2RB8=1,说明该帧是地址帧,地址信息可以进入 S2BUF,并使 S2RI为1,进而在中断服务程序中再进行地址号比较;
②若S2RB8=0,说明该帧不是地址帧,应丢掉且保持S2RI=0。在模式1 中,如果S2SM2位为0且S2REN位为1,接收收机处于地址帧筛选被禁止状态。
  不论收到的S2RB8 为0或1,均可使接收到的信息进入 S2BUF,并使 S2RI=1,此时 S2RB8通常为校验位。模式0 为非多机通信方式,在这种方式时,要设置S2SM2应为0。
S2REN:允许/禁止串口接收控制位
  0:禁止串口接收数据
  1:允许串口接收数据
S2TB8:当串口2使用模式1时,S2TB8为要发送的第9位数据,一般用作校验位或者地址帧/数据帧标志位,按需要由软件置位或清0。在模式0中,该位不用。
S2RB8:当串口2使用模式1时,S2RB8为接收到的第9位数据,一般用作校验位或者地址帧/数据帧标志位。在模式0中,该位不用。
S2TI:串口2发送中断请求标志位。在停止位开始发送时由硬件自动将S2TI置1,向CPU发请求中断,响应中断后S2TI必须用软件清零
S2RI:串口2接收中断请求标志位。串行接收到停止位的中间时刻由硬件自动将S2RI置1,向CPU发中断申请,响应中断后S2RI必须由软件清零

4.2.2 串口2数据寄存器(S2BUF)

在这里插入图片描述

S2BUF:串口1数据接收(发送缓冲区。S2BUF实际是2个缓冲器,读缓冲器和写缓冲器,两个操作分别对应两个不同的寄存器,1个是只写寄存器(写缓冲器),1个是只读寄存器(读缓冲器)。对S2BUF 进行读操作,实际是读取串口接收缓冲区,对S2BUF进行写操作则是触发串口开始发送数据。

4.2.3 辅助寄存器(AUXR)

在这里插入图片描述

T2R:定时器2的运行控制位
  0:定时器2停止计数
  1:定时器2开始计数
T2x12:定时器2速度控制位
  0:12T模式,即CPU时钟12分频(FOSC/12)
  1: 1T模式,即CPU时钟不分频分频(FOSC/1)
S1ST2:串口1波特率发生器选择位**(串口2不需要)**
  0:选定时器1作为波特率发生器
  1:选定时器2作为波特率发生器

5.3 串口2模式0波特率计算

  串行口2的模式0为8位数据位可变波特率UART工作模式。此模式一帧信息为10位:1位起始位,8位数据位(低位在先)和1位停止位。波特率可变,可根据需要进行设置波特率。TxD2为数据发送口,RxD2为数据接收口,串行口全双工接受/发送。
  串口2的波特率是可变的,其波特率由定时器2产生。当定时器采用1T模式时(12倍速),相应的波特率的速度也会相应提高12倍。

在这里插入图片描述

5.4 串口中断系统

4.4.1 中断使能寄存器

在这里插入图片描述

ES2:串行口2中断允许位
  0:禁止串口2中断
  1:允许串口2中断

4.4.2 串口控制寄存器

在这里插入图片描述

TI:串口1发送完成中断请求标志。需要软件清零。
RI:串口1接收完成中断请求标志。需要软件清零。
S2TI:串口2发送完成中断请求标志。需要软件清零。
S2RI:串口2接收完成中断请求标志。需要软件清零。
S3TI:串口3发送完成中断请求标志。需要软件清零。
S3RI:串口3接收完成中断请求标志。需要软件清零。
S4TI:串口4发送完成中断请求标志。需要软件清零。
S4RI:串口4接收完成中断请求标志。需要软件清零。

4.4.3 中断优先级寄存器

在这里插入图片描述

PS2H,PS2:串口2中断优先级控制位
  00:串口2中断优先级为0级(最低级)
  01:串口2中断优先级为1级(较低级)
  10:串口2中断优先级为2级(较高级)
  11:串口2中断优先级为3级(最高级)

5.5 示例代码

bit		busy;		//定义二进制数据
char	wptr;
char	rptr;
char	buffer[16];
//串口初始化程序
void UartInit(void)		//[email protected]
{
	IP2 |= 0x01;		//中断优先级,优先级为3最高级
	IP2H |= 0x01;
	T2L = BRT;			//BRT为独立波特率发生器的溢出率。
	T2H = BRT >> 8;		//设置定时器初始值
	AUXR = 0x14;		//开启定时器2的IT模式
	S2CON = 0x10;		//使能串口接收
	IE2 |= 0x01;		//使能串口中断
	EA = 1;				//开启全局中断
}
//串口发送字节数据
void Uart2Send(char dat)
{
	while(busy);
	busy = 1;
	S2BUF = dat;
}
//串口发送字符串
void Uart2SendStr(char *p)
{
	while(*p)
	{
		Uart2Send(*p++)
	}
}
//串口中断程序
void UART2_ISR(void) interrupt 8
{
	if(S2CON & 0x02)		
	{
		S2CON &= (uint8)(~0x02);	//清中断标志位
		busy = 0;
	}
	if(S2CON & 0x01)
	{
		S2CON &= (uint8)(~0x01);	//清中断标志位
		buffer[wptr++] = S2BUF;
		wptr &= 0x0f;
	}
}

六、SPI通信

6.1 SPI通信方式

  1. 单主单从(一个主机设备连接一个从机设备)
    在这里插入图片描述

主机设置:SSIG设置为1,MSTR设置为1,固定为主机模式。主机可以使用任意端口连接从机的SS管脚,拉低从机的SS脚即可使能从机

从机设置:SSIG设置为0,SS管脚作为从机的片选信号。

  1. 互为主从

在这里插入图片描述

设置方法1:两个设备初始化时都设置为SSIG设置为0,MSTR 设置为1,且将SS 脚设置为双向口模式输出高电平。此时两个设备都是不忽略SS的主机模式。当其中一个设备需要启动传输时,可将自己的SS脚设置为输出模式并输出低电平,拉低对方的SS脚,这样另一个设备就被强行设置为从机模式了。

设置方法2:两个设备初始化时都将自己设置成忽略SS的从机模式,即将SSIG设置为1,MSTR设置为0。当其中一个设备需要启动传输时,先检测SS管脚的电平,如果时候高电平,就将自己设置成忽略SS的主模式,即可进行数据传输了。

  1. 单主多从

在这里插入图片描述

主机设置:SSIG设置为1,MSTR设置为1,固定为主机模式。主机可以使用任意端口分别连接各个从机的SS管脚,拉低其中一个从机的SS脚即可使能相应的从机设备

从机设置:SSIG设置为0,SS管脚作为从机的片选信号。

6.2 SPI相关寄存器

6.2.1 状态寄存器(SPSTAT)

在这里插入图片描述

SPIF:SPI中断标志位。
  当发送/接收完成1字节的数据后,硬件自动将此位置1,并向CPU提出中断请求。当SPI处于主机模式且SSIG位被设置为0时,如果SS管脚的输入电平被驱动为低电平时,此标志位也会被硬件自动置1,以标志设备模式发生变化。
  注意:此标志位必须用户通过软件方式向此位写1进行清零。
WCOL:SPI写冲突标志位。
  当SPI在进行数据传输的过程中写SPDAT寄存器时,硬件将此位置1。
  注意:此标志位必须用户通过软件方式向此位写1进行清零。

6.2.2 SPI控制寄存器(SPCTL),SPI速度控制

在这里插入图片描述

SSIG:SS引脚功能控制位
  0:SS引脚确定器件是主机还是从机
  1:忽略SS引脚功能,使用MSTR确定器件是主机还是从机
SPEN:SPI使能控制位
  0:关闭SPI功能
  1:使能SPI功能
DORD:SPI数据位发送/接收的顺序
  0:先发送/接收数据的高位(MSB)
  1:先发送/接收数据的低位(LSB)
MSTR:器件主/从模式选择位
设置主机模式:
  若SSIG=0,则SS管脚必须为高电平且设置MSTR为1
  若SSIG=1,则只需要设置MSTR为1(忽略SS管脚的电平)
设置从机模式:
  若SSIG=0,则SS管脚必须为低电平(与MSTR位无关)
  若SSIG=1,则只需要设置MSTR为0(忽略SS管脚的电平)
CPOL:SPI时钟极性控制
  0:SCLK空闲时为低电平,SCLK的前时钟沿为上升沿,后时钟沿为下降沿
  1:SCLK空闲时为高电平,SCLK的前时钟沿为下降沿,后时钟沿为上升沿
CPHA:SPI时钟相位控制
  0:数据SS管脚为低电平驱动第一位数据并在SCLK的后时钟沿改变数据,前时钟沿采样数据(必须SSIG=0)
  1:数据在SCLK的前时钟沿驱动,后时钟沿采样

SPR[1:0]:SPI时钟频率选择
在这里插入图片描述

6.2.3 SPI数据寄存器(SPDAT)

在这里插入图片描述

6.3 配置寄存器

在这里插入图片描述
(1)从机模式的注意事项:
  当CPHA=0时,SSIG必须为0(即不能忽略SS 脚)。在每次串行字节开始还发送前SS 脚必须拉低,并且在串行字节发送完后须重新设置为高电平。SS管脚为低电平时不能对SPDAT寄存器执行写操作,否则将导致一个写冲突错误。CPHA=0且SSIG=1时的操作未定义。
  当CPHA=1时,SSIG可以置1(即可以忽略脚)。如果SSIG=0,SS 脚可在连续传输之间保持低有效(即一直固定为低电平)。这种方式适用于固定单主单从的系统。
(2)主机模式的注意事项:
  在SPI中,传输总是由主机启动的。如果SPI使能(SPEN=1)并选择作为主机时,主机对SPI数据寄存器SPDAT的写操作将启动SPI时钟发生器和数据的传输。在数据写入SPDAT之后的半个到一个SPI 位时间后,数据将出现在 MOSI脚。写入主机 SPDAT寄存器的数据从 MOSI 脚移出发送到从机的 MOSI 脚。同时从机SPDAT寄存器的数据从MISO脚移出发送到主机的MISO脚。
  传输完一个字节后,SPI时钟发生器停止,传输完成标志(SPIF)置位,如果SPI中断使能则会产生一个SPI中断。主机和从机 CPU的两个移位寄存器可以看作是一个16位循环移位寄存器。当数据从主机移位传送到从机的同时,数据也以相反的方向移入。这意味着在一个移位周期中,主机和从机的数据相互交换。
(3)通过SS改变模式
  如果SPEN=1,SSIG=0且MSTR=l,SPI使能为主机模式,并将SS 脚可配置为输入模式化或准双向口模式。这种情况下,另外一个主机可将该脚驱动为低电平,从而将该器件选择为SPI从机并向其发送数据。为了避免争夺总线,SPI系统将该从机的MSTR清零,MOSI和SCLK强制变为输入模式,而MISO则变为输出模式,同时SPSTAT的SPIF标志位置1。
  用户软件必须一直对MSTR位进行检测,如果该位被一个从机选择动作而被动清零,而用户想继续将SPI作为主机,则必须重新设置MSTR位,否则将一直处于从机模式。
(4)写冲突
  SPI 在发送时为单缓冲,在接收时为双缓冲。这样在前一次发送尚未完成之前,不能将新的数据写入移位寄存器。当发送过程中对数据寄存器 SPDAT进行写操作时,WCOL 位将被置1以指示发生数据写冲突错误。在这种情况下,当前发送的数据继续发送,而新写入的数据将丢失。
  当对主机或从机进行写冲突检测时,主机发生写冲突的情况是很罕见的,因为主机拥有数据传输的完全控制权。但从机有可能发生写冲突,因为当主机启动传输时,从机无法进行控制。
  接收数据时,接收到的数据传送到一个并行读数据缓冲区,这样将释放移位寄存器以进行下一个数据的接收。但必须在下个字符完全移入之前从数据寄存器中读出接收到的数据,否则,前一个接收数据将丢失。
  WCOL可通过软件向其写入"1"清零。

6.4 示例代码

//SPI初始化
void SPI_Init(void)
{
	SPCTL = 0x50;		//使能SPI主机模式
//	SPCTL = 0x40;		//使能SPI从机模式
	SPSTAT = 0xC0; 		//清中断标志
//	IE2 = ESPI;			//使能SPI中断,没有即查询模式
	EA = 1}
//SPI中断函数
void SPI_ISR() interrupt 9
{
	SPSTAT = 0xC0; 
	SS = 1;
	busy = 0;
	LED = !LED;
}
//查询方式函数
while(1)
{
	SS = 0;						//拉低从机SS管脚
	SPDAT = 0x5a;
	while(!(SPSTAT & 0x80));
	SPSTAT = 0xc0;
	SS = 1;
	LED = !LED;
}

七、EEPROM

7.1 EEPROM简介

  STC8H 系列单片机内部集成了大容量的 EEPROM。利用 ISP/IAP技术可将内部 Data Flash 当EEPROM,擦写次数在10万次以上。EEPROM可分为若干个扇区,每个扇区包含512字节。
  注意:EEPROM的写操作只能将字节中的1写为0,当需要将字节中的0写为1,则必须执行扇区擦除操作。EEPROM的读/写操作是以1字节为单位进行,而EEPROM擦除操作是以1扇区(512字节)为单位讲行,在执行擦除操作时,如果目标扇区中有需要保留的数据,则必须预先将这些数据读取到 RAM 中暂存,待擦除完成后再将保存的数据和需要更新的数据一起再写回EEPROM/DATA-FLASH。
  所以在使用 EEPROM 时,建议同一次修改的数据放在同一个扇区,不是同一次修改的数据放在不同的扇区,不一定要用满。数据存储器的擦除操作是按扇区进行的(每扇区512字节)。
  EEPROM可用于保存一些需要在应用过程中修改并且掉电不丢失的参数数据。在用户程序中,可以对EEPROM进行字节读/字节编程/扇区擦除操作。在工作电压偏低时,建议不要进行EEPROM操作,以免发送数据丢失的情况。

EEPROM操作时间
■ 读取1字节:4个系统时钟(使用MOVC指令读取更方便快捷)
■ 编程1字节:约30~40us(实际的编程时间为6~7.5us,但还需要加上状态转换时间和各种控制信号的SETUP和HOLD时间)
■ 擦除1扇区(512字节):约4~6ms
  EEPROM操作所需时间是硬件自动控制的,用户只需要正确设置IAP TPS寄存器即可。IAP_TPS=系统工作频率/1000000(小数部分四舍五入进行取整)
例如:系统工作频率为12MHz,则IAP_TPS设置为12

7.2 EEPROM相关寄存器

在这里插入图片描述

7.2.1 EEPROM数据寄存器(IAP_DATA)

在这里插入图片描述

  在进行EEPROM的读操作时,命令执行完成后读出的EEPROM数据保存在IAPDATA寄存器中。
  在进行EEPROM的写操作时,在执行写命令前,必须将待写入的数据存放在IAPDATA寄存器中,再发送写命令。擦除 EEPROM命令与IAP DATA寄存器无关。

7.2.2 EEPROM地址寄存器(IAP_ADDR)

在这里插入图片描述

  EEPROM进行读、写、擦除操作的目标地址寄存器。IAP ADDRH保存地址的高字节,IAP ADDRL 保存地址的低字节

7.2.3 EEPROM命令寄存器(IAP_CMD)

在这里插入图片描述

CMD[1:0]:发送EEPROM操作命令
  00:空操作
  01:读EEPROM命令。读取目标地址所在的1字节。
  10:写EEPROM命令。写目标地址所在的1字节。注意:写操作只能将目标字节中的1写为0,而不能将0写为1。一般当目标字节不为FFH时,必须先擦除。
  11:擦除 EEPROM。擦除目标地址所在的1页(1扇区/512字节)。注意:擦除操作会一次擦除1个扇区(512字节),整个扇区的内容全部变成FFH。

7.2.4 EEPROM触发寄存器(IAP_TRIG)

在这里插入图片描述

  设置完成 EEPROM 读、写、擦除的命令寄存器、地址寄存器、数据寄存器以及控制寄存器后,需要向触发寄存器IAP TRIG依次写入5AH、A5H(顺序不能交换)两个触发命令来触发相应的读、写、擦除操作。操作完成后,EEPROM地址寄存器 IAP ADDRH、IAP ADDRL 和 EEPROM 命令寄存器IAP_CMD 的内容不变。如果接下来要对下一个地址的数据进行操作,需手动更新地址寄存器IAP_ADDRH和寄存器IAP_ADDRL的值。
  注意:每次EEPROM操作时,都要对IAPTRIG先写入5AH,再写入A5H,相应的命令才会生效。写完触发命令后,CPU会处于IDLE等待状态,直到相应的IAP操作执行完成后CPU才会从IDLE状态返回正常状态继续执行CPU指令。

7.2.5 EEPROM控制寄存器(IAP_CONTR)

在这里插入图片描述

IAPEN:EEPROM操作使能控制位
  0:禁止EEPROM操作
  1:使能EEPROM操作
SWBS:软件复位选择控制位,(需要与SWRST配合使用)
  0:软件复位后从用户代码开始执行程序
  1:软件复位后从系统ISP监控代码区开始执行程序
SWRST:软件复位控制位
  0:无动作
  1:产生软件复位
CMD FAIL:EEPROM操作失败状态位,需要软件清零
  0:EEPROM操作正确
  1:EEPROM操作失败

7.2.6 EEPROM等待事件控制寄存器(IAP_TPS)

在这里插入图片描述

需要根据工作频率进行设置
若工作频率为12MHz,则需要将IAP_TPS设置为12;若工作频率为24MHz,则需要将IAP_TPS设置为24,其他频率以此类推。

7.3 EEPROM大小及地址

  STC8H系列单片机内部均有用于保存用户数据的EEPROM。内部的EEPROM有3 操作方式读、写和擦除,其中擦除操作是以扇区为单位进行操作,每扇区为512字节,即每执行一次擦除命令就会擦除一个扇区,而读数据和写数据都是以字节为单位进行操作的,即每执行一次读或者写命令时只能读出或者写入一个字节。
  STC8H系列单片机内部的EEPROM的访问方式有两种:IAP方式和MOVC方式。IAP方式可对EEPROM执行读、写、擦除操作,但MOVC只能对EEPROM进行读操作,而不能讲行写和擦除操作。无论是使用IAP方式还是使用MOVC方式访问 EEPROM,首先都需要设置正确的目标地址。IAP方式时,目标地址与EEPROM实际的物理地址是一致的,均是从地址0000H开始访问,但若要使用 MOVC 指令进行读取 EEPROM数据时,目标地址必须是在 EEPROM实际的物理地址的基础上还有加上程序大小的偏移。下面以STC8H1K16这个型号为例,对目标地址进行详细说明:
在这里插入图片描述
  STC8H1K16的程序空间为16K字节(0000h~3FFFh),EEPROM空间为12K(0000h-2FFh)。当需要对 EEPROM物理地址1234h的单元进行读、写、擦除时,若使用IAP方式进行访问时,设置的目标地址为1234h,即IAP ADDRH设置12h,IAP ADDRL设置34h,然后设置相应的触发命令即可对1234h 单元进行正确操作了。但若是使用MOVC方式读取EEPROM的1234h单元,则必须在1234h的基础上还有加上ROM空间的大小4000h,即必须将DPTR设置为5234h,然后才能使用MOVC指令进行读取。
  注意:由于擦除是以512字节为单位进行操作的,所以执行擦除操作时所设置的目标地址的低9位是无意义的。例如: 执行擦除命令时,设置地址1234H/1200H/1300H/13FFH,最终执行擦除的动作都是相同的,都是擦除1200H~13FFH这512字节。
  不同型号内部EEPROM的大小及访问地址会存在差异,针对各个型号EEPROM的详细大小和地址请参考下表

在这里插入图片描述

7.4 示例代码

//关闭IAP
void IapIdle()
{
    IAP_CONTR = 0;                  //关闭IAP功能
    IAP_CMD = 0;                    //清除命令寄存器
    IAP_TRIG = 0;                   //清除触发寄存器
    IAP_ADDRH = 0x80;               //将地址设置到非IAP区域
    IAP_ADDRL = 0;
}
BYTE IapReadByte(WORD addr)
{
    BYTE dat;                       //

    IAP_CONTR = 0x80;         		//使能IAP
	IAP_TPS = 12;					//设置等待参数12MHz
    IAP_CMD = CMD_READ;             //设置IAP读命令
    IAP_ADDRL = addr;               //设置IAP低地址
    IAP_ADDRH = addr >> 8;          //设置IAP高地址
    IAP_TRIG = 0x5a;                //写触发命令(0x5a)
    IAP_TRIG = 0xa5;
    _nop_();                        
    dat = IAP_DATA;                 //读IAP数据
    IapIdle();                      //关闭IAP功能
    return dat; 
}
void IapProgramByte(WORD addr, BYTE dat)
{
    IAP_CONTR = 0x80;         		//使能IAP
	IAP_TPS = IAP_DELAY;			//设置等待参数
    IAP_CMD = CMD_PROGRAM;          //设置IAP写命令
    IAP_ADDRL = addr;               //设置IAP低地址
    IAP_ADDRH = addr >> 8;          //设置IAP高地址
    IAP_DATA = dat;                 //写IAP数据
    IAP_TRIG = 0x5a;                //写触发命令(0x5a)
    IAP_TRIG = 0xa5;
    IAP_TRIG = 0xa5;
    _nop_();  
    IapIdle();
}
void IapEraseSector(WORD addr)
{
    IAP_CONTR = 0x80;         		//使能IAP
	IAP_TPS = IAP_DELAY;			//设置等待参数
    IAP_CMD = CMD_ERASE;            //设置IAP擦除命令
    IAP_ADDRL = addr;               //设置IAP低地址
    IAP_ADDRH = addr >> 8;          //设置IAP高地址
    IAP_TRIG = 0x5a;                //写触发命令(0x5a)
    IAP_TRIG = 0xa5; 
    _nop_(); 
    IapIdle();
}

附录

1、STC8H参考手册

https://download.csdn.net/download/weixin_44567668/87430907

2、C语言基础

https://blog.csdn.net/weixin_44567668/article/details/129003611

;