vb2002
发表于 2024-6-4 01:00:27
看了你的按键控制多个模式
如果就一个按键,可以控制吗?
比如默认熄灭,按一下打开led用模式 1闪,再按 模式 2闪,再按模式 3闪
未元星系
发表于 2024-6-4 07:35:41
vb2002 发表于 2024-6-4 01:00
看了你的按键控制多个模式
如果就一个按键,可以控制吗?
比如默认熄灭,按一下打开led用模式 1闪,再按 模 ...
可以的,定义一个按键次数变量,按一下按键给它加一,用if()检测就可以
未元星系
发表于 2024-6-4 07:58:07
本帖最后由 未元星系 于 2024-6-4 08:03 编辑
vb2002 发表于 2024-6-4 00:58
为什么你学的这么快,我学的那么慢啊
我可能是因为之前跟着b站江协科技的教程学了两遍51单片机(STC89C52),所以有些单片机基础;另外我找到了一套教程,b站布丁橘长的,在咱们论坛里上方的教学视频里的“屠龙刀演示”也是,虽然是讲STC32G单片机的,但基础方面和我学的8H差不多,时长很短但全是干货,也推荐你看看。最后是看看数据手册,对应的功能看明白了就学得很快。
soma
发表于 2024-6-4 08:19:25
vb2002 发表于 2024-6-4 01:00
看了你的按键控制多个模式
如果就一个按键,可以控制吗?
比如默认熄灭,按一下打开led用模式 1闪,再按 模 ...
这个不就是标志位算法吗
vb2002
发表于 2024-6-4 09:03:12
未元星系 发表于 2024-6-4 07:58
我可能是因为之前跟着b站江协科技的教程学了两遍51单片机(STC89C52),所以有些单片机基础;另外我找到了 ...
基础我也有点了
就像老师讲的,一看就懂,一写就废~{:4_167:}
vb2002
发表于 2024-6-4 09:04:45
soma 发表于 2024-6-4 08:19
这个不就是标志位算法吗
标志位算法
如果加上储存功能呢?
比如按一下换挡(记忆),5秒后没换档,下一次按就关灯.
再下一次按就是开机,打开上一次记忆的模式
vb2002
发表于 2024-6-4 09:07:42
未元星系 发表于 2024-5-27 22:57
自学开天斧第⑤课:
学习内容:1、外部中断
学习简介:STC8H8K64U单片机内置五个外部中断,INT0,INT1,INT2, ...
我记得电容可以做硬件消抖
按键两端并上0.1uf电容
小涵子爸爸
发表于 2024-6-4 09:15:43
{:4_250:}
未元星系
发表于 2024-6-4 11:54:09
vb2002 发表于 2024-6-4 09:07
我记得电容可以做硬件消抖
按键两端并上0.1uf电容
挺好的办法
未元星系
发表于 2024-6-4 22:30:10
本帖最后由 未元星系 于 2024-6-4 22:35 编辑
自学开天斧第⑩课:
学习内容:1、串口DMA发送与接收
学习简介:串口通信是单片机和电脑通信的常用方法,但当需要一次发送的数据总量很大时,就会严重占用主程序时间,为了避免这个问题,我们可以将需要串口发送的数据存到DMA里发送,这样会提高单片机运行效率,减少主函数占用。串口DMA一次最多可以发送或接收256字节数据(可自行调整为小于256字节的数据)
实验项目:单片机向串口发送256字节数据->P2口灯亮灭两次->检测DMA输入(若有输入则打印在串口上)
实验重点:为体现DMA使用对主程序效率的影响,串口波特率设置为9600
程序代码:
#include <STC8H.H>
#include <stdio.h>
#define MAIN_Fosc 24000000L
#define BRT (65536 - (MAIN_Fosc / 9600+2) / 4)
#define DMA_AMT_LEN 255 // DMA传输总字节(AMT+1) 9999+1=10000字节
unsigned char xdata DMABuffer_send; // DMA发送缓存 DMA数据存放在XRAM(XDATA区域),需要使用关键字xdata
unsigned char xdata DMABuffer_review; //DMA接收缓存
unsigned int j,k;
bit busy;
bit B_1ms; // 1毫秒标志
bit DmaTxFlag; // 发送完成标志
bit DmaRxFlag; // 接收完成标志
//unsigned int numb;
unsigned char Rx_cnt; // Rx接收计数
unsigned char RX_TimeOut;
void Delay_ms(unsigned int ms)
{
unsigned int a;
do{
a = MAIN_Fosc / 10000;
while(--a);
}while(--ms);
}
void Timer0_Init(void) // 1毫秒@24MHz
{
AUXR |= 0x80;//设置定时器为1T模式,即不分频
TMOD &= 0xF0;//保留高四位(定时器1),低四位全为0:设置定时器/计数器0为定时器、GATE置0、16位自动重装模式
TL0 = 0x3F; //初始值65535 - 24000 = 41535 = 1010 0010 0011 1111,即高8位为0xA2,低8位为0x3F
TH0 = 0xA2; //
TF0 = 0; //清零TF0中断标志位
TR0 = 1; //定时器开始计时
ET0 = 1; //开启定时器0中断
}
void Blink()
{unsigned char i;for(i = 0;i < 4;i++){P2 = ~P2;Delay_ms(100);}}//P2口灯亮灭两次
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;
}
void DMA_Config(void)
{
DMA_UR1T_CFG = 0x80; // bit7 1:使能串口1DMA发送中断
DMA_UR1T_STA = 0x00; // 清零串口1DMA发送完成中断标志、清零数据覆盖中断标志
DMA_UR1T_AMT =DMA_AMT_LEN; // 设置传输总字节数:n+1
DMA_UR1T_TXAH = (unsigned char)((unsigned int)&DMABuffer_send >> 8); // 设置传输数据的源地址,高8位
DMA_UR1T_TXAL = (unsigned char)((unsigned int)&DMABuffer_send); // 设置传输数据的源地址,低8位
DMA_UR1T_CR = 0xc0; // bit7 1:使能串口1DMA发送, bit6 1:开始DMA自动发送
DMA_UR1R_CFG = 0x80; // bit7 1:使能串口1DMA接收中断
DMA_UR1R_STA = 0x00; // 清零串口1DMA接收完成中断标志、清零数据丢弃中断标志
DMA_UR1R_AMT =DMA_AMT_LEN; // 设置传输总字节数:n+1
DMA_UR1R_RXAH = (unsigned char)((unsigned int)&DMABuffer_review >> 8); // 设置传输数据的目标地址,高8位
DMA_UR1R_RXAL = (unsigned char)((unsigned int)&DMABuffer_review); // 设置传输数据的目标地址,低8位
DMA_UR1R_CR = 0xa1; //bit7 1:使能串口1DMA接收, bit5 1:开始DMA自动接收, bit0 1:清除 FIFO
}
void main()
{
P3M0 = 0x00; P3M1 = 0x00;
P2M0 = 0x00; P2M1 = 0x00;
P_SW2 |= 0x80; //使能XFR
ES = 1; // 使能串口1中断
EA = 1; // 使能EA总中断
Timer0_Init();
Uart1Init();
DMA_Config();
DmaTxFlag = 0; // 清零发送完成标志
DmaRxFlag = 0; // 清零接收完成标志
for(k = 0;k < 256; k++) // 200个字符
{
DMABuffer_send = k%128; // 200个字符,为128个ASCII字符
}
while (1)
{
DmaTxFlag = 1;
DmaRxFlag = 1;
if((DmaTxFlag) && (DmaRxFlag)) // 当发送和接收完成标志均为1时,表示空闲
{
DmaTxFlag = 0; // 清零发送完成标志
DMA_UR1T_CR = 0xc0; // bit7 1:使能 UART1_DMA, bit6 1:开始 UART1_DMA 自动发送
DmaRxFlag = 0; // 清零接收完成标志
DMA_UR1T_CR = 0xa1; // bit7 1:使能 UART1_DMA, bit5 1:开始 UART1_DMA 自动接收, bit0 1:清除 FIFO
}
Blink();
DmaTxFlag = 0; // 清零发送完成标志
DmaRxFlag = 0; // 清零接收完成标志
if((DmaTxFlag) && (DmaRxFlag)) // 当发送和接收完成标志均为1时,表示空闲
{
Rx_cnt = 0; // 清零接收计数
RX_TimeOut = 0; // 清零接收超时计数
DmaTxFlag = 0; // 清零发送完成标志
DMA_UR1T_CR = 0xc0; // bit7 1:使能 UART1_DMA, bit6 1:开始 UART1_DMA 自动发送
DmaRxFlag = 0; // 清零接收完成标志
DMA_UR1R_CR = 0xa1; // bit7 1:使能 UART1_DMA, bit5 1:开始 UART1_DMA 自动接收, bit0 1:清除 FIFO
}
if(B_1ms) //1ms 到
{
B_1ms = 0;
if(RX_TimeOut > 0) // 超时计数
{
if(--RX_TimeOut == 0) // 接收超时计数
{
DMA_UR1R_CR = 0x00; // 关闭 UART1_DMA
printf("\n以下是已接收到的数\xFD据:\r\n"); // UART1 发送 一个字符串,\xFD用于补全汉字‘数’的编码,防止出现乱码
for(j=0;j<Rx_cnt;j++) printf("%bc",DMABuffer_review); // 将接收到的数据,发送给PC端
printf("\r\n"); // 数据发送完成后,发送回车、换行符
Rx_cnt = 0; // 清零接收计数
DMA_UR1R_CR = 0xa1; //bit7 1: 使能UART1_DMA,bit5 1: 开始 UART1_DMA 自动接收,bit0 1: 清除 FIFO
}
}
}
}
}
void Timer0_Routine(void) interrupt 1
{
B_1ms = 1; // 1毫秒标志
}
void Uart1Isr() interrupt 4
{
if (TI == 1){TI = 0;busy = 0;}
if (RI == 1)
{
RI = 0;
Rx_cnt++; // 接收计数+1
if(Rx_cnt > DMA_AMT_LEN) {Rx_cnt = 0;} // 接收计数大于等于DMA缓冲区长度,清零接收计数
RX_TimeOut = 5; // 如果 5ms 没收到新的数据,判定一串数据接收完毕x = 1;}
}
}
void UART1_DMA_Interrupt(void) interrupt 13 // 串口DMA中断号大于31,借用13号保留中断中转
{
if (DMA_UR1T_STA & 0x01) // 发送完成中断标志为1时
{
DMA_UR1T_STA &= ~0x01; // 清零发送完成中断标志
DmaTxFlag = 1; // 发送完成标志置1
}
if (DMA_UR1T_STA & 0x04) // 数据覆盖中断标志为1时
{
DMA_UR1T_STA &= ~0x04; // 清零数据覆盖中断标志
}
if (DMA_UR1R_STA & 0x01) // 接收完成中断标志为1时
{
DMA_UR1R_STA &= ~0x01; // 清零接收完成中断标志
DmaRxFlag = 1; // 接收完成标志置1
}
if (DMA_UR1R_STA & 0x02) // 数据丢弃中断标志为1时
{
DMA_UR1R_STA &= ~0x02; // 清零数据丢弃中断标志
}
}
实验现象:单片机向串口发送256字节数据->P2口灯亮灭两次->检测DMA输入(若有输入则打印在串口上),串口发送接收数据不打断P2口LED按其频率闪烁