未元星系
发表于 2024-6-6 21:43:49
自学开天斧第11课:
学习内容:1、EEPROM
学习简介:EEPROM,掉电不丢失存储器,可存储重要数据,STC8H8K64U可将内部多余Flash空间设置通过isp/iap设为EEPROM,本次将介绍isp设置。
学习重点:1、EEPROM擦除操作按扇区为单位,一个扇区为512字节。
2、写入操作只能将1写为0,不能将0写为1.
3、EEPROM起始地址为0x0000.
实验项目:创建四个变量,分别对应不同数据,将它们依次存入EEPROM的四个字节中并读取,从P2口LED显示出来。
实验重点:1、本次使用了STC8H8K64U的EEPROM库函数。
2、烧录两次代码,第一次为以下代码,第二次将擦除和写入环节注释或删除再次烧录。
3、STC-ISP需要配置,取消“下次下载程序时擦除用户EEPROM区”勾选选项,取消“清除EEPROM缓冲区”勾选选项
程序代码:
#include <STC8H.H>
#include <intrins.h>
#include "EEPROM.h"
#define MAIN_Fosc 24000000L
unsigned char num1 = 0x03; // 0000 0011
unsigned char num2 = 0x0c; // 0000 1100
unsigned char num3 = 0x30; // 0011 0011
unsigned char num4 = 0xc0; // 1100 0000
unsigned char num;
void main()
{
P2M0 = 0x00; P2M1 = 0x00;
P3M0 = 0x00; P3M1 = 0x00;
P2 = 0xff;
P3 |= 0x3c;
P_SW2 |= 0x80;
EEPROM_SectorErase(0x0000);
EEPROM_write_n(0x0000+0,&num1,1);
EEPROM_write_n(0x0000+1,&num2,1);
EEPROM_write_n(0x0000+2,&num3,1);
EEPROM_write_n(0x0000+3,&num4,1);
while(1)
{
if(P35 == 0){EEPROM_read_n(0x0000+0,&num,1);}
if(P34 == 0){EEPROM_read_n(0x0000+1,&num,1);}
if(P33 == 0){EEPROM_read_n(0x0000+2,&num,1);}
if(P32 == 0){EEPROM_read_n(0x0000+3,&num,1);}
P2 = ~num;
}
}
程序效果:四个按键控制每2个两位亮,注释掉擦除和写入函数烧录后,效果仍存在。
备注:库函数在附加文件中,也可以在论坛上方的“本地下载”中找寻相关单片机库函数。
victormore
发表于 2024-6-7 15:13:28
学习了,谢谢
未元星系
发表于 2024-6-8 23:03:15
昨天和今天已初步学习ADC检测电压,但目前很疲惫,需要休息,明天再来记录。{:4_216:}
未元星系
发表于 2024-6-9 22:29:11
自学开天斧第12课:
学习内容:1、ADC
学习简介:ADC可用于模拟信号转化数字信号,检测电压,检测光、温湿度等。之前学的STC89C52单片机需要外接IC才能使用ADC功能,但8H内部集成了16通道10/12位ADC,可以通过配置相关功能的寄存器来调用ADC功能,测量模拟量。
实验项目:单片机ADC测量15通道1.19V内部电压,并通过串口打印在电脑屏幕上。
实验重点:使用ADC库函数。
程序代码:
#include <STC8H.H>
#include <stdio.h>
#include "ADC.h"//STC8H的ADC库函数头文件
#define MAIN_Fosc 24000000L
#define BRT (65536 - (MAIN_Fosc / 115200+2) / 4)
int delay_ms;
float ADC_data;
bit busy;
bit B_1ms;
void Timer0_Init(void) // 1毫秒@24MHz
{
AUXR |= 0x80; // 定时器时钟1T模式
TMOD &= 0xF0; // 设置定时器模式
TL0 = 0x3F; // 设置定时初始值
TH0 = 0xA2; // 设置定时初始值
TF0 = 0; // 清除TF0标志
TR0 = 1; // 定时器0开始计时
ET0 = 1; // 使能定时器0中断
}
void Uart1Init() // UART1初始化
{
P_SW1 &= 0x3F; //设置串口1引脚为P3.0,P3.1
SCON = 0x50; // 模式1(8位数据)、接收使能
PCON |= 0x00; //设置波特率不加倍,关闭帧错检测功能
T2L = BRT;
T2H = BRT >> 8; // 波特率对应的重装载值
AUXR |= 0x15;
busy = 0; // 清零忙标志
}
void UartPutc(unsigned char dat)//串口打印字符函数
{
busy = 1;
SBUF = dat;
while(!TI);
TI = 0;
busy = 0;
}
char putchar(char c){ UartPutc(c); return c; }//重构putchar函数
void ADC_Init(void)
{
ADC_InitTypeDef ADC_1V; //定义结构体存放ADC命令
ADC_1V.ADC_SMPduty = 10; //采样时间控制
ADC_1V.ADC_Speed = ADC_SPEED_2X16T; //工作时钟频率(系统时钟2*16分频)
ADC_1V.ADC_AdjResult = ADC_LEFT_JUSTIFIED; //ADC结果调整(12位数据左对齐)
ADC_Inilize(&ADC_1V); //初始化ADC_1V
}
void main()
{
P2M0 = 0x00; P2M1 = 0x00;
P3M0 = 0x00; P3M1 = 0x00;
P_SW2 |= 0x80;
EA = 1;
Timer0_Init();//定时器0初始化
Uart1Init(); //串口1初始化
ADC_Init(); //ADC初始化
ADC_PowerControl(ENABLE);//使能ADC
while(1)
{
ADC_data = Get_ADCResult(ADC_CH15);//采样15通道(1.19V内部电压)ADC数据
if(B_1ms == 1)
{
B_1ms = 0;
delay_ms++;
if(delay_ms >= 100)//每100毫秒发送一次数据
{
delay_ms = 0;
printf("U = %1.4fV",2.5 * ADC_data / 4096); //打印获取数据的计算结果(2.5是因为开天斧板子的verf接了别的电路,基准电压2.5V)
}
}
}
}
void Timer0_Routine(void) interrupt 1
{B_1ms = 1;}
void Uart1Isr() interrupt 4
{if (TI == 1){TI = 0;busy = 0;} if (RI == 1){RI = 0;}}
未元星系
发表于 2024-6-11 22:20:23
临近考试,可能得暂时失踪一段时间了。
未元星系
发表于 2024-6-13 15:55:14
本帖最后由 未元星系 于 2024-6-13 15:57 编辑
自学开天斧第13课:
学习内容:1、RTC
学习简介:STC8H8K64U内部集成了RTC时钟,可以通过配置相关寄存器实现年月日时分秒的显示,还可以进行闹钟设置。本次只学习设置和显示RTC时钟
实验项目:通过配置RTC寄存器单片机RTC显示年、月、日、时、分、秒、并将数据通过Printf打印在串口助手上
实验重点:使用内部32K振荡器(这里同样可以使用外部的,更准确)
程序代码:
#include <STC8H.H>
#include <stdio.h>
#define MAIN_Fosc 24000000L
#define BRT (65536 - (MAIN_Fosc / 115200+2) / 4)
bit busy;
bit B_1ms;
int delay_num;
void Timer0_Init(void) // 配置定时器0(24MHZ),周期1ms
{AUXR |= 0x80;TMOD &= 0xF0;TL0 = 0x3F;TH0 = 0xA2;TF0 = 0;TR0 = 1;ET0 = 1;}
void Uart1Init() // UART1初始化
{P_SW1 &= 0x3F;SCON = 0x50;PCON |= 0x00; T2L = BRT;T2H = BRT >> 8;AUXR |= 0x15;busy = 0;}
void UartPutc(unsigned char dat) //串口发送数据
{busy = 1;SBUF = dat;while(!TI);TI = 0;busy = 0;}
char putchar(char c) //重构putchar函数
{UartPutc(c);return c;}
void RTC_Init(void) //配置RTC
{
IRC32KCR = 0x80; //启动内部低速振荡器
while(!(IRC32KCR & 0x01)); //等待时钟稳定
RTCCFG |= 0x02; //选择内部低速IRC
INIYEAR = 24; //设置年(00-99)
INIMONTH = 6; //设置月(00-12)
INIDAY = 12; //设置日(00-31)
INIHOUR = 23; //设置时(00-23)
INIMIN = 2; //设置分(00-59)
INISEC = 40; //设置秒(00-59)
RTCCFG |= 0x01; //将设置的时间写入RTC
RTCIF = 0; //RTC中断清零
RTCCR = 0x01; //启动RTC
}
void main()
{
P_SW2 |= 0x80;
P0M0 = 0x00; P0M1 = 0x00;
P1M0 = 0x00; P1M1 = 0x00;
Timer0_Init();
Uart1Init();
RTC_Init(); //RTC初始化
EA = 1; //开启总中断
while(1)
{
if(B_1ms)
{
B_1ms = 0;
delay_num ++;
if(delay_num >= 500)
{
delay_num = 0;
printf("20%bd年%bd月%bd日%bd时%bd分%bd秒\r\n",YEAR,MONTH,DAY,HOUR,MIN,SEC);
}
}
}
}
void Timer0_Routine(void) interrupt 1
{B_1ms = 1; }
void Uart1Isr() interrupt 4
{
if (TI == 1){TI = 0; busy = 0;}
if (RI == 1){RI = 0;}
}
程序效果:串口助手每500ms打印一次时间
未元星系
发表于 2024-7-16 23:30:49
继续开始记录开天斧的学习进程:
这两周因为考试等因素暂停了更新,从明天开始会继续更新,以下有几点变化:
①、开发板我添加了元件,焊接了排针、排母、五向开关,增加了尼龙柱。
②、增添了一些模块和设备,例:逻辑分析仪、STC USB转双串口下载器、OLED模块(0.96寸,SSD1602芯片)
③、近几天初步学习了I2C协议OLED的使用,后期的学习将减少对串口助手的依赖,直接将相关数据和信息显示在OLED屏幕上。
④、学习重点也有了适当调整:暑假期间学习重点为单片机内置资源,不同的是这次学习力求以配置寄存器的方法学会对每个单独外设的使用和多种外设组合使用。
未元星系
发表于 2024-7-17 23:01:10
本帖最后由 未元星系 于 2024-7-18 08:30 编辑
自学开天斧第14课:
学习内容:定时器详解(一)
学习简介:前期初步学习过定时器相关部分内容,本次学习旨在加深印象以及学习额外的定时器功能。
实验项目:通过定时器0做1ms定时,在P3.5口输出500HZ方波,同时利用这个延时在OLED上打印每秒递增的数据。
实验重点:OLED的使用,定时器0的配置
程序代码:
#include <STC8H.H>
#include "OLED.h"
bit Timer0_1ms;
void Timer0_Init(void)//时钟40M,定时1ms
{
AUXR |= 0x80; //设置定时器0为1T模式,不分频
TMOD &= 0xF0; //保留TMOD定时器模式寄存器高八位,清零第八位,即:设置定时器0为定时器,GATE=0,16位自动重装模式
TL0 = 0xbf; //65535-40000=25535,即0110 0011 1011 1111,高八位赋值给TH0,低八位赋值给TL0
TH0 = 0x63;
TF0 = 0; //清空定时器溢出标志位
TR0 = 1; //将定时器运行控制位置1
ET0 = 1; //打开定时器0中断
INTCLKO &= 0xff;//保留中断与时钟输出寄存器8位
INTCLKO |= 0x01;//打开定时器0时钟输出控制,即定时器0溢出时,P3.5口翻转
}
void main()
{
unsigned char num;//每秒递增变量
unsigned int delay; //延时变量(1秒)
P_SW2 |= 0x80; //打开特殊功能寄存器
P2M0 = 0x00; P2M1 = 0x00;
P3M0 = 0x00; P3M1 = 0x00;
Timer0_Init(); //初始化定时器0
OLED_Init();//屏幕初始化
OLED_ColorTurn(0);//0正常显示,1 反色显示
OLED_DisplayTurn(0);//0正常显示 1 屏幕翻转显示
OLED_Clear();//清空屏幕
EA = 1;//开启总中断
OLED_ShowString(0,0,"num = ",16);
OLED_ShowNum(43,0,num,3,16);
while(1)
{
if(Timer0_1ms==1)
{
Timer0_1ms = 0;
delay++;
if(delay>=1000)
{
delay = 0;
num++;
OLED_ShowNum(43,0,num,3,16);
}
}
}
}
void Timer0_Routine(void) interrupt 1
{
Timer0_1ms = 1;
}
未元星系
发表于 2024-7-18 19:36:55
本帖最后由 未元星系 于 2024-7-18 19:39 编辑
自学开天斧第15课:
学习内容:定时器详解(二)
学习简介:本次学习Timer1做定时器和Timer0做计数器功能。
实验项目:通过定时器1做1ms定时,并在P3.4口时钟输出500HZ方波,主函数利用此延时使变量num每500毫秒加一;
同时定时器0做计数器,时钟来源为P3.4,下降沿触发,并在定时器0中断函数中翻转P3.3口输出250HZ方波,同时在P3.5时钟输出250HZ方波
实验重点:定时器0和定时器1共同使用。
程序代码:
#include <STC8H.H>
#include "OLED.h"
bit Timer1_1ms;
void Timer0_Init(void)//做计数器
{
AUXR |= 0x80;
TMOD &= 0xF0;
TMOD |= 0x04; // C/T = 1,设Timer0为计数模式
TL0 = 0xff;
TH0 = 0xff;
TF0 = 0;
TR0 = 1;
ET0 = 1;
INTCLKO &= 0xff;
INTCLKO |= 0x01;//启动T0 P35时钟输出
}
void Timer1_Init(void)//时钟40M,定时1ms
{
AUXR |= 0x40;
TMOD &= 0x0f;
TL1 = 0xbf;
TH1 = 0x63;
TF1 = 0;
TR1 = 1;
ET1 = 1;
INTCLKO &= 0xff;
INTCLKO |= 0x02; //启动T1 P34时钟输出
}
void main()
{
unsigned char num;
unsigned int delay;
P_SW2 |= 0x80;
P2M0 = 0x00; P2M1 = 0x00;
P3M0 = 0x00; P3M1 = 0x00;
Timer0_Init();
Timer1_Init();
OLED_Init();//屏幕初始化
OLED_ColorTurn(0);//0正常显示,1 反色显示
OLED_DisplayTurn(0);//0正常显示 1 屏幕翻转显示
OLED_Clear();//清空屏幕
EA = 1;
OLED_ShowString(0,0,"num = ",16);
OLED_ShowNum(43,0,num,3,16);
while(1)
{
if(Timer1_1ms==1)
{
Timer1_1ms = 0;
delay++;
if(delay>=500)//500毫秒延时
{
delay = 0;
num++;
OLED_ShowNum(43,0,num,3,16);
}
}
}
}
void Timer0_Routine(void) interrupt 1
{
P33=~P33;//翻转P33口
}
void Timer1_Routine(void) interrupt 3
{
Timer1_1ms = 1;
}
未元星系
发表于 2024-7-19 23:13:32
自学开天斧记录:
今天计划学习定时器测量脉宽以及使用定时器T2,但出现了一些问题,今日已得到大佬的指点,明天会继续学习。