未元星系
发表于 2024-7-20 18:39:07
本帖最后由 未元星系 于 2024-7-20 18:42 编辑
自学开天斧第16课:
学习内容:定时器详解(三)
学习简介:STC8H8K64U的五个定时器中的T2、T3、T4有八位的预分频寄存器,可以设置预分频从而定时更长的时间,本次学习Timer2做定时器定时1秒。
实验项目:通过定时器2做1s定时,并在中断函数中翻转P3.5口,主函数利用此延时使变量time每秒加一并显示在OLED上;
实验重点:预分频寄存器、STC8H8K64U单片机定时器T2的注意事项
程序代码:
#include <STC8H.H>
#include "OLED.h"
#define ET2 0x04 //定时器2中断开关需要(详情可见开天斧官方例程)
bit Timer2_1s;
unsigned int time;
void Timer2_Init(void)//时钟40M,定时1s
{
AUXR |= 0x00;//设置定时器2为12T模式
TM2PS = 0xfa;//设置预分频250
T2L = 0x55; //装载初始值52309
T2H = 0xcc;
AUXR |= 0x10;//启动定时器
IE2|=ET2; //使能T2中断
}
void main()
{
P_SW2 |= 0x80;
P1M0 = 0x00; P1M1 = 0x00;
P2M0 = 0x00; P2M1 = 0x00;
P3M0 = 0x00; P3M1 = 0x00;
OLED_Init();//屏幕初始化
OLED_ColorTurn(0);//0正常显示,1 反色显示
OLED_DisplayTurn(0);//0正常显示 1 屏幕翻转显示
OLED_Clear();//清空屏幕
EA = 1;
OLED_ShowString(0,2,"Time = ",16);
OLED_ShowNum(56,2,time,5,16);
while(1)
{
if(Timer2_1s==1)
{
Timer2_1s = 0;
time++;
OLED_ShowNum(56,2,time,5,16);
}
}
}
void Timer2_Routine(void) interrupt 12
{
Timer2_1s = 1;
P35 = ~P35;
}
未元星系
发表于 2024-7-20 22:50:15
本帖最后由 未元星系 于 2024-7-20 22:51 编辑
自学开天斧第17课:
学习内容:定时器详解(四)
学习简介:T3、T4做定时模式输出时钟,并用逻辑分析仪检测。
实验项目:T3做1000HZ输出时钟,T4做500HZ输出时钟。
实验重点:T3/T4功能脚切换
程序代码:
#include <STC8H.H>
void Timer3_Init(void)
{
T3T4PIN = 0x01;//调整T3、T4时钟输出口分别为P01、P03
T4T3M &= 0xf0;
T4T3M |= 0x03;
T3L = 0xdf; //定时0.5ms
T3H = 0xb1;
T4T3M |= 0x08;
}
void Timer4_Init(void)
{
T3T4PIN = 0x01; //调整T3、T4时钟输出口分别为P01、P03
T4T3M &= 0x0f;
T4T3M |= 0x30;
T4L = 0xbf; ////定时1ms
T4H = 0x63;
T4T3M |= 0x80;
}
void main()
{
P_SW2 |= 0x80;
P0M0 = 0x00; P0M1 = 0x00;
Timer3_Init();
Timer4_Init();
while(1){}
}
未元星系
发表于 2024-7-21 14:39:57
本帖最后由 未元星系 于 2024-7-21 20:39 编辑
自学开天斧第18课:
学习内容:IO口中断、五向开关
学习简介:①、STC8H8K64U单片机每个IO口均有独立中断,本次以P7口为例学习。
②、开天斧板载了一个五向开关的接口(出厂时不带,需自行焊接),连接的五个引脚为P70-P74。
实验重点:①、IO口中断(要点:Keil5无法编译中断号大于31的程序,可通过添加汇编文件中转IO口到13号保留中断)
②、五向开关(要点:板载五向开关的板子后面有五颗0欧姆电阻需要一起焊接上,如果没有,也可以直接用焊锡短接)
实验项目:五向开关通过IO口中断控制P2口LED亮灭(按下键翻转P2口、按上键翻转P26口、按下键翻转P20口、按左键翻转24口、按右键翻转P22口)
实验缺陷:中断启动可能受按键抖动影响,需要添加防抖措施(视频中肉眼可见)
程序代码:
#include <STC8H.H>
#include "intrins.h"
void main()
{
P_SW2 |= 0x80;
P7M0 = 0x00; P7M1 = 0x00;
P2M0 = 0x00; P2M1 = 0x00;
P7 |= 0x1f; //P70-P74口为高电平
P7IM0 = 0x00; //设置P7口中断为下降沿触发
P7IM1 = 0x00;
P7INTE = 0x1f;//开启P70-P74 口中断
EA = 1;
while(1){;}
}
void P7_isr(void) interrupt 13
{
unsigned char intf;
intf = P7INTF;//获取P7口中断信号
if(intf)
{
P7INTF = 0x00;
if(intf&0x01)//P7.0中键
{
P2 = ~P2;
}
if(intf&0x02)//P7.1右键
{
P22 = ~P22;
}
if(intf&0x04)//P7.2左键
{
P24 = ~P24;
}
if(intf&0x08)//P7.3下键
{
P20 = ~P20;
}
if(intf&0x10)//P7.4上键
{
P26 = ~P26;
}
}
}
//汇编文件内容:
CSEG AT 0163H;将P7口44号中断地址0163H中转到13号中断地址0068H
JMP 006BH
END
jxdaya123
发表于 2024-7-21 17:51:15
加油{:4_250:}
未元星系
发表于 2024-7-21 20:40:57
jxdaya123 发表于 2024-7-21 17:51
加油
嗯嗯{:4_168:}
未元星系
发表于 2024-7-22 23:27:29
今日已开始串口的新一轮学习,虽然遇到各种问题,但也能一一化解,明天会继续学习。
未元星系
发表于 2024-7-23 13:30:11
本帖最后由 未元星系 于 2024-7-23 13:32 编辑
自学开天斧第19课:
学习内容:串口通信详解(一)、定时器扫描独立按键(来自b站江协科技)、STC USB转双串口下载器
学习简介:之前简单了解了UART1向电脑发送和接收数据的功能,本轮计划学习UART2、UART3、UART4的使用
实验重点:①、UART2向电脑收发(printf)数据
②、定时器扫描独立按键,按键控制单片机向电脑发送数据
③、单片机和电脑通过一箭双雕USB转双串口下载器的第二组串口连接调试(下载器TXD2接P4.7,RXD2接P4.6,使用时注意在串口助手中更换串口号)
实验项目:①、单片机P35口按下,单片机向电脑printf打印一次数据
②、电脑串口助手向单片机发送16进制数据,单片机P2口LED随数据亮灭
程序代码:
#include <STC8H.H>
#include <stdio.h>
#define MAIN_Fosc 40000000L
#define BRT (65536 - (MAIN_Fosc / 115200+2) / 4)
bit busy;
bit x;
sbit KEY1 = P3^5;
unsigned char number1; // 测试变量,发送次数 unsigned char 类型
unsigned char str[] = "STC8H8K64U-开天斧3.2"; // 字符串数组
unsigned char Key_KeyNumber; //独立按键检测
void Timer0_Init(void) // 1毫秒@40MHz
{
AUXR |= 0x80; // 定时器时钟1T模式
TMOD &= 0xF0; // 设置定时器模式
TL0 = 0xbf;
TH0 = 0x63; // 设置定时初始值
TF0 = 0; // 清除TF0标志
TR0 = 1; // 定时器0开始计时
ET0 = 1; // 使能定时器0中断
}
void Uart2_Init() // UART2初始化
{
S2CON = 0x10; // 模式1(8位数据)、接收使能
T2L = BRT;
T2H = BRT >> 8; // 波特率对应的重装载值
AUXR |= 0x14; //打开定时器2(波特率发生器)
IE2 |= 0x01; // 使能串口2中断
P_SW2 |= 0x01; //设置串口2引脚为P4.6,P4.7
busy = 0; // 清零忙标志
}
void UartPutc(unsigned char dat) //串口发送数据
{
while(busy);
busy = 1;
S2BUF = dat;
}
char putchar(char c) //重构的putchar函数(需引stdio.h头文件)
{
UartPutc(c);
return c;
}
unsigned char Key(void)//返回获取到的按键值
{
unsigned char Temp=0;
Temp=Key_KeyNumber;
Key_KeyNumber=0;
return Temp;
}
unsigned char Key_GetState(void)//获取按键值
{
unsigned char KeyNumber=0;
if(P35==0){KeyNumber=1;}
if(P34==0){KeyNumber=2;}
if(P33==0){KeyNumber=3;}
if(P32==0){KeyNumber=4;}
return KeyNumber;
}
void Timer_Key(void)//定时器循环扫描函数
{
static unsigned char NowState,LastState;
LastState=NowState; //按键状态更新
NowState=Key_GetState(); //获取当前按键状态
//如果上个时间点按键按下,这个时间点未按下,则是松手瞬间,以此避免消抖和松手检测
if(LastState==1 && NowState==0){Key_KeyNumber=1;}
if(LastState==2 && NowState==0){Key_KeyNumber=2;}
if(LastState==3 && NowState==0){Key_KeyNumber=3;}
if(LastState==4 && NowState==0){Key_KeyNumber=4;}
}
void main()
{
unsigned char getkey;
P_SW2 |= 0x80;
P1M0 = 0x00; P1M1 = 0x00;
P2M0 = 0x00; P2M1 = 0x00;
P3M0 = 0x00; P3M1 = 0x00;
P4M0 = 0x00; P4M1 = 0x00;
P2 = 0xff;
EA = 1; // 使能EA总中断
Timer0_Init();
Uart2_Init();
while(1)
{
getkey = Key();
if(getkey==1)
{
getkey=0;
number1++; // 每次发送后number1+1
printf("\n");
printf("第%bu次发送\r ",number1); // 发送unsigned char类型
printf("%s\r ",str); // 发送字符串"STC8H8K64U-开天斧三.2"
printf("HelloWorld!\r\n\n"); // 发送字符串"HelloWorld!"
}
if(x == 1)
{
x = 0;
P2 = ~S2BUF;
}
}
}
void Timer0_Routine(void) interrupt 1
{
static unsigned int T0_count1;
T0_count1++;
if(T0_count1>=20){Timer_Key();}//隔20毫秒扫描一次按键状态达到延时效果
}
void Uart2_Routine() interrupt 8 //UART2中断
{
if (S2CON & 0x02) // 发送中断标志置1时
{
S2CON &= ~0x02; // 清零发送中断标志
busy = 0; // 清零忙状态
}
if (S2CON & 0x01) // 接收中断标志置1时
{
S2CON &= ~0x01;
x = 1;
}
}
未元星系
发表于 2024-7-24 19:24:35
本帖最后由 未元星系 于 2024-7-24 19:29 编辑
自学开天斧第20课:
学习内容:串口通信详解(二):双机通信
学习简介:开天斧开发板 和 STC一箭双雕USB转双串口下载器 主控均为STC8H8K64U单片机,只是封装不同,所以STC双串口下载器也可以看作一个开发板进行代码编写和烧录(按住Download按键后再断一下电源即可进入下载模式),本次用这两个开发板初步学习单片机串口的双机通信
实验重点:①、相关串口的初始化配置(UART2)
②、两个开发板的连线(TXD2连RXD2、RXD2连TXD2、GND相连)(备注:双串口下载器的串口引脚丝印与其单片机相反)
③、两个开发板烧录同样的代码
④、为避免下载器的按键检测与LED和UART2产生干扰,使用自制的独立按键模块(本次实验使用P34引脚,低电平触发)
实验项目:①、开天斧按下P34按键,UART2向双串口下载器发送字符‘1’,下载器P36和P37口LED翻转
②、下载器按下P34(检测到低电平),UART2向开天斧发送字符‘1’,开天斧P2口8个LED翻转
程序代码:
#include <STC8H.H>
bit busy;
bit x;
void Delay(unsigned int ms)
{unsigned int i; do{i = MAIN_Fosc / 10000;while(--i);}while(--ms);}
void Uart2_Init() // UART1初始化
{
S2CON = 0x10; // 模式1(8位数据)、接收使能
T2L = BRT;
T2H = BRT >> 8; // 波特率对应的重装载值
AUXR |= 0x14;
IE2 |= 0x01; // 使能串口1中断
P_SW2 &= 0xfe; //设置串口1引脚为P1.0,P1.1
busy = 0; // 清零忙标志
}
void Uart2Putc(unsigned char dat)
{
while(busy);
busy = 1;
S2BUF = dat;
}
void main()
{
P_SW2 |= 0x80;
P1M0 = 0x00; P1M1 = 0x00;
P2M0 = 0x00; P2M1 = 0x00;
P3M0 = 0x08; P3M1 = 0x00; //P33口配置为推挽模式
P4M0 = 0x00; P4M1 = 0x00;
P5M0 = 0x00; P5M1 = 0x00;
P13 = 1;P14 = 1;P34 = 1;P54 = 0; //初始化自制独立按键模块
P33 = 1; //下载器LED供电
EA = 1; // 使能EA总中断
Uart2_Init();
while(1)
{
if(P34==0)
{
while(P34==0){;} //为减少代码篇幅,本次使用阻塞延时,上期笔记已介绍定时器扫描按键的延时
Delay(20); //----------------------------------------------------------------------------------------------
Uart2Putc('1');
}
if(x == 1)
{
P36 = ~P36;
P37 =~P37;
P2 = ~P2;
x = 0;
}
}
}
void Uart2_Routine() interrupt 8
{
if (S2CON & 0x02) // 发送中断标志置1时
{
S2CON &= ~0x02; // 清零发送中断标志
busy = 0; // 清零忙状态
}
if (S2CON & 0x01) // 接收中断标志置1时
{
S2CON &= ~0x01;
x = 1;
}
}
未元星系
发表于 2024-7-25 18:33:21
本帖最后由 未元星系 于 2024-7-25 18:35 编辑
自学开天斧第21课:
学习内容:串口通信详解(三):UART3、UART4
学习简介:前两天已学习串口2的使用,串口3和串口4的使用方法与串口2类似,这里只保留UART3、UART4实验成功后的初始化函数和中断函数
程序代码:
bit busy3;
bit busy4;
void Uart3_Init() // UART3初始化
{
S3CON = 0x10; //8位数据, 使用Timer2做波特率发生器, 允许接收
//S3CON = 0x50; //8位数据, 使用Timer3做波特率发生器, 允许接收
T2L = BRT;
T2H = BRT >> 8;
AUXR |= 0x14; //开启Timer2
IE2 |= 0x08; //允许UART3中断
P_SW2 |= 0x02; //UART3引脚配置为P0.0 P0.1
busy3 = 0; // 清零忙标志
}
void Uart4_Init() // UART4初始化
{
S4CON = 0x10; //8位数据, 使用Timer2做波特率发生器, 允许接收
T2L = BRT;
T2H = BRT >> 8;
AUXR |= 0x14;
IE2 |= 0x10; //允许UART4中断
P_SW2 &= ~0x04; //UART4 switch bit2 to: 0: P0.2 P0.3
busy4 = 0; // 清零忙标志
}
//----------------------------------------------------中断函数--------------------------------------------------//
void Uart3_Routine(void) interrupt 17
{
if(S3CON & 0x01) //接收数据
{
S3CON &= ~0x01;
}
if(S3CON & 0x02) //发送数据
{
S3CON &= ~0x02;
busy3 = 0;
}
}
void Uart4_Routine(void) interrupt 18
{
if(S4CON & 0x01) //接收数据
{
S4CON &= ~0x01;
}
if(S4CON & 0x02) //发送数据
{
S4CON &= ~0x02;
busy4 = 0;
}
}
未元星系
发表于 2024-7-28 23:08:47
自学开天斧第22课:
学习内容:RTC详解+无源蜂鸣器(定时器控制IO)+OLED显示
学习简介:本次学习STC8H8K64U内部RTC,在OLED上显示时间,启动闹钟,到点蜂鸣器鸣叫
实验项目:①、通过配置RTC在OLED显示时间 ②、设置闹钟,到点开启Timer0输出时钟给无源蜂鸣器IO口提供振动(P35) ③、开启闹钟中断,到点时蜂鸣器按规律鸣叫(停300ms,叫200ms)
④、开启秒中断,每秒P20口LED翻转一次 ⑤、按下P34按键关闭闹钟蜂鸣
实验重点:RTC中断、定时器&无源蜂鸣器
程序代码:
#include <STC8H.H>
#include "OLED.h"
sbit IO_buzzer = P3^5;
sbit VCC_buzzer = P5^1;
sbit GND_buzzer = P3^6;
bit Buzzer_delay;
bit Key_delay;
bit Alarm;
unsigned int Buzzer_off_count;
unsigned int Buzzer_on_count;
unsigned int Key_count;
unsigned char SEC_past;
unsigned char SEC_now;
void Timer0_Init(void)//时钟40M,定时1ms
{
AUXR |= 0x80;
TMOD &= 0xF0;
//TMOD |= 0x04;
TL0 = 0xbf;
TH0 = 0x63;
TF0 = 0;
TR0 = 1;
ET0 = 1;
INTCLKO &= 0xff;
INTCLKO &= 0xfe;
}
void RTC_Init(void)
{
IRC32KCR = 0x80; //启动内部低速振荡器
while(!(IRC32KCR & 0x01)); //等待时钟稳定
RTCCFG |= 0x02; //选择内部低速IRC
INIYEAR = 24; //设置年(00-99)
INIMONTH = 6; //设置月(1-12)
INIDAY = 12; //设置日(1-31)
INIHOUR = 18; //设置时(0-24) //设置时间:18点23分0秒
INIMIN = 23; //设置分(0-60)
INISEC = 0; //设置秒(0-60)
RTCCFG |= 0x01; //将设置的时间写入RTC
RTCIF = 0; //RTC中断清零
RTCCR = 0x01; //启动RTC
RTCIEN |= 0x88; //使能闹钟中断、秒中断
ALAHOUR = 18; //定闹钟为18点23分3秒
ALAMIN = 23;
ALASEC = 3;
}
void main()
{
P_SW2 |= 0x80;
P0M0 = 0x00; P0M1 = 0x00;
P1M0 = 0x00; P1M1 = 0x00;
P2M0 = 0x00; P2M1 = 0x00;
P3M0 = 0x00; P3M1 = 0x00;
P4M0 = 0x00; P4M1 = 0x00;
P5M0 = 0x02; P5M1 = 0x00; //P51配置成推挽输出
P6M0 = 0x00; P6M1 = 0x00;
P34 = 1;
VCC_buzzer = 1; GND_buzzer = 0;
OLED_Init();
OLED_ColorTurn(0);//0正常显示,1 反色显示
OLED_DisplayTurn(0);//0正常显示 1 屏幕翻转显示
OLED_Clear();
Timer0_Init();
RTC_Init();
EA = 1;
OLED_ShowString(0,0,"Hello world !",16);
OLED_ShowChar(34,3,':',16);
OLED_ShowChar(60,3,':',16);
while(1)
{
SEC_past = SEC_now;
SEC_now= SEC;
if(SEC_past != SEC_now)
{
OLED_ShowNum(17,3,HOUR,2,16);
OLED_ShowNum(43,3,MIN,2,16);
OLED_ShowNum(69,3,SEC,2,16);
}
if(Alarm == 1)
{
if(Buzzer_delay == 1)
{
Buzzer_delay = 0;
if(~(INTCLKO | 0xfe))
{
Buzzer_off_count++;
if(Buzzer_off_count>= 300)//蜂鸣器关闭__ms
{
Buzzer_off_count = 0;
INTCLKO |= 0x01;
}
}
if(INTCLKO & 0x01)
{
Buzzer_on_count++;
if(Buzzer_on_count >= 200)//蜂鸣器开启__ms
{
Buzzer_on_count = 0;
INTCLKO &= 0xfe;
}
}
}
if(P34==0)
{
if(Key_delay==1)
{
Key_delay = 0;
Key_count++;
if(Key_count >= 20)
{
Key_count=0;
Alarm = 0;
INTCLKO &= 0xfe;
VCC_buzzer = 0;
IO_buzzer = 1;
}
}
}
}
}
}
void Timer0_Routine(void) interrupt 1
{
Buzzer_delay = 1;
Key_delay = 1;
}
void RTC_isp(void) interrupt 13
{
if(RTCIF & 0x80)
{
RTCIF &= ~0x80;
Alarm = 1;
}
if(RTCIF & 0x08)
{
RTCIF &= ~0x08;
P20 = ~P20;
}
}