找回密码
 立即注册
楼主: 晨露

STC8H单片机教程学习打卡

[复制链接]
已绑定手机

6

主题

167

回帖

600

积分

高级会员

积分
600
 楼主| 发表于 2025-2-28 21:09:51 | 显示全部楼层

2025.01.22开始学习第16讲
一、STC8H8K64U的定时/计数器应用举例
定时器11.0592最长18s
真正的功能是在中断服务程序中实现

定时器定时量程的扩展
1.软件扩展方法
        一个定时器的输出当做另一个定时器的输入。
        对中断进行计数
2.硬件扩展方法

微信截图_20250122204853.png 微信截图_20250122210010.png
微信截图_20250122213129.png 微信截图_20250122214507.png


回复

使用道具 举报 送花

已绑定手机

6

主题

167

回帖

600

积分

高级会员

积分
600
 楼主| 发表于 2025-3-14 23:25:03 | 显示全部楼层
第17讲 串行通信的分类2

2025.03.10
1.STC 8H8K64U单片机集成了
4个异步串行通信接口(UART)
1个SPI通信口
1个I2C接口
1个USB接口
2.串行通信的相关概念
基本的数据通信方式有两种
  通讯(数字、数据、其他的信息交换的方法)和通信的区别
  并行通信--数据的各位同时传送
  串行通信--数据一位一位地顺序传送(从低位开始发送),设备必须共地
  RS232一般15米,最长不超过30米
  RS485/9600  传输距离1000米(常见的32个节点)
3.串行通信的分类
①按照通信格式的同步方式分类:异步通信、同步通信
  异步通信,每一个字符都要用起始位(0)和停止位(1)作为字符开始和结束的标志,它们是以字符为单位一个个地发送和接收的。
  7位数据格式串行通信传输(0-127),8位数据格式串行通信传输(0-255),大于255的数可以分成2个字节传输。
  在异步数据传送中,CPU与外设之间事先必须约定好以下内容:
   字符格式:双方要设定好字符的编码形式、奇偶校验形式、起始位和停止位的规定。
   通信速率:通常使用波特率来表示。
    表示方法 9600(bps),n(没有校验位,e偶,o奇校验),8(8个数据位),1(停止位)
  同步通信,效率高,但线路复杂,适合于近距离通信。
   同步传送时需要注意的是:收发双方必须使用相同的同步字符,在同步传送中要求用同步时钟来实现发送端和接收端之间的严格同步,而且对同步时钟脉冲信号的相位一致性要求非常严格。
   同步字符1---同步字符2---n个数据字节---校验字节1---校验字节2
②按照数据的传送方向分类:单工(只允许数据按一个固定方向传送)、半双工(数据可以从A到B,也可以从B到A,但同一时刻只能向一个方向传送)、全双工(数据可同时在两个方向传送)
    还可以分为多终端半双工通信、多终端全双工通信   
4.通用异步接收器/发送器UART
UART(Universal Asynchronous Receiver/Transmitter)通用的异步接收器/发送器

姚总补充,多机通信时Tx侧加二极管
   
屏幕截图 2025-03-10 173120.png 屏幕截图 2025-03-10 173430.png
屏幕截图 2025-03-10 180114.png 屏幕截图 2025-03-10 180325.png

屏幕截图 2025-03-10 180608.png 屏幕截图 2025-03-10 180640.png

屏幕截图 2025-03-10 180855.png 屏幕截图 2025-03-10 181219.png



回复

使用道具 举报 送花

已绑定手机

6

主题

167

回帖

600

积分

高级会员

积分
600
 楼主| 发表于 2025-3-29 22:38:24 | 显示全部楼层


2025.03.14-3.29陆续学习
第18讲
多机通信,RXD和TXD连接注意事项

本节内容
一、STC8H8K64U单片机的串口简介
        沿用15系列单片机,4个UART全双工
        串口1有四种工作模式
        串口2-4只有两种工作模式(UART)
        串口分时复用
二、STC8H8K64U的UART(串行)接口的寄存器
        SCON SBUF重点关注
        单机通信选择模式1,多机通信选模式3
        串口通信涉及定时器,定时器涉及中断,所以先学中断
        位传送,MOV指令中出现C,位寻址中必须有C的参与
三、STC8H8K64U单片机的串口工作模式
        起始位检测的重要性,起始位检测错了,后边的数据就
都有问题了。(设计了下降延传输检测器)

微信截图_20250314220130.png 微信截图_20250314220453.png

微信截图_20250314222027.png 微信截图_20250314225011.png

微信截图_20250314225122.png 微信截图_20250315073253.png

微信截图_20250315073445.png 微信截图_20250315074352.png

微信截图_20250315074442.png 微信截图_20250315075534.png

微信截图_20250316195430.png 微信截图_20250316195509.png

微信截图_20250316195614.png 微信截图_20250316195713.png

微信截图_20250316195734.png 微信截图_20250316195826.png

微信截图_20250317074702.png 微信截图_20250317074824.png

微信截图_20250317075154.png 微信截图_20250317075211.png

微信截图_20250317075407.png 微信截图_20250329220807.png

微信截图_20250329221355.png 微信截图_20250329222000.png


回复

使用道具 举报 送花

已绑定手机

6

主题

167

回帖

600

积分

高级会员

积分
600
 楼主| 发表于 2025-4-6 21:07:16 | 显示全部楼层
2025.03.30
第19讲
串口通信、多机通信

一、波特率的设定
        串口1常用模式1和3,波特率可变。编程时应注意,当定时器作为波特率发生器使用时,应禁止定时器产生中断(ET1=0或ET2=0)注意此处ET1和ET2不能直接写,因为其不能按位寻址。

二、UART接口的应用举例
        在编程应用中,虽然可以采用查询的方式进行通信,但是,为了进行实时任务处理,一般采用中断方式进行串行通信程序设计。
        (1)串口1的编程要点
                在中断服务程序中要有清除中断标志指令(将T1和R1清0)
        (2)串口2的编程要点
               
                补充:串口2在使用时,相关I/O口的设置,默认是高阻输入。
微信截图_20250330222958.png 微信截图_20250330223511.png
微信截图_20250330223816.png 微信截图_20250330224030.png
微信截图_20250330224653.png 微信截图_20250331222840.png
微信截图_20250331223504.png 微信截图_20250331223534.png
微信截图_20250331224122.png 微信截图_20250331224633.png
微信截图_20250331224721.png 微信截图_20250331224756.png
微信截图_20250405221930.png 微信截图_20250405222045.png
微信截图_20250405222155.png 微信截图_20250405222317.png
微信截图_20250405222425.png 微信截图_20250405222840.png
微信截图_20250405223321.png 微信截图_20250405223532.png
微信截图_20250405223548.png 微信截图_20250405223624.png
微信截图_20250405223658.png 微信截图_20250405223744.png
微信截图_20250405223922.png 微信截图_20250405223946.png
微信截图_20250405224919.png 微信截图_20250405224929.png
微信截图_20250405224956.png 微信截图_20250405225702.png
微信截图_20250405230102.png




回复

使用道具 举报 送花

已绑定手机

6

主题

167

回帖

600

积分

高级会员

积分
600
 楼主| 发表于 2025-4-28 12:05:25 | 显示全部楼层
定时器中断触发原理
在 51 单片机中,定时器中断的触发流程如下:

  • 定时器配置:对定时器的工作模式、初值等进行设置。
  • 计数操作:定时器开启后,依据系统时钟频率和预分频系数开始计数。
  • 中断触发:当计数值达到最大值(溢出)时,会置位定时器溢出标志位。
  • 中断响应:若中断允许,单片机就会暂停当前程序,转而执行对应的定时器中断服务程序。
  • 中断返回:中断服务程序执行完毕后,单片机返回主程序继续执行。

简单示例
下面是一个 51 单片机定时器 0 的简单示例,该示例将定时器 0 设置为模式 1(16 位定时器),每 50ms 触发一次中断,在中断服务程序中对一个变量进行计数,计满 20 次(即 1 秒)时,翻转 P1.0 引脚的电平。
  1. #include <reg51.h>
  2. // 定义定时器0溢出次数计数器
  3. unsigned char count = 0;
  4. // 定时器0中断服务程序
  5. void timer0_isr() interrupt 1 {
  6.     // 重新加载初值,以实现每50ms触发一次中断
  7.     TH0 = (65536 - 50000) / 256;
  8.     TL0 = (65536 - 50000) % 256;
  9.     count++;
  10.     if (count >= 20) {
  11.         // 每1秒翻转一次P1.0引脚的电平
  12.         P1 ^= 0x01;
  13.         count = 0;
  14.     }
  15. }
  16. void main() {
  17.     // 配置定时器0为模式1
  18.     TMOD = 0x01;
  19.     // 加载初值,以实现每50ms触发一次中断
  20.     TH0 = (65536 - 50000) / 256;
  21.     TL0 = (65536 - 50000) % 256;
  22.     // 使能定时器0中断
  23.     ET0 = 1;
  24.     // 使能全局中断
  25.     EA = 1;
  26.     // 启动定时器0
  27.     TR0 = 1;
  28.     while (1) {
  29.         // 主循环可以处理其他任务
  30.     }
  31. }
复制代码
代码解释
  • 头文件包含:#include <reg51.h>包含了 51 单片机的寄存器定义。
  • 全局变量:count用于记录定时器 0 的溢出次数。
  • 中断服务程序:timer0_isr()是定时器 0 的中断服务程序,当中断触发时会执行该程序。在程序里,重新加载定时器初值,使定时器每 50ms 溢出一次;对count进行计数,计满 20 次(即 1 秒)时,翻转 P1.0 引脚的电平,并将count清零。
  • 主函数:
    • 配置定时器 0 为模式 1。
    • 加载定时器初值,让定时器每 50ms 溢出一次。
    • 使能定时器 0 中断和全局中断。
    • 启动定时器 0。
    • 进入无限循环,主循环可处理其他任务。


这个示例展示了如何使用 51 单片机的定时器 0 产生中断,并在中断服务程序中执行特定任务。


定时器 0 每 50ms 触发一次计数并非定时器本身固有的特点,而是通过对定时器进行一系列设置来实现的。下面为你详细说明在 51 单片机里如何设置以达成每 50ms 触发一次计数。
关键设置因素
1. 工作模式选择
51 单片机的定时器有多种工作模式,不同模式下定时器的计数范围和功能有所不同。以定时器 0 为例,一般选用模式 1(16 位定时器模式),因为该模式计数范围较大,能够满足较长时间间隔的定时需求。
2. 初值计算与加载
定时器的计数是从初始值开始的,当计数值达到最大值(对于 16 位定时器,最大值为 65535)时会产生溢出中断。要实现每 50ms 触发一次中断,就需要根据单片机的晶振频率来计算并加载合适的初值。

假设单片机的晶振频率为 11.0592MHz,机器周期是晶振周期的 12 倍,即机器周期 屏幕截图 2025-04-28 141647.png

要定时 50ms,需要的机器周期数 屏幕截图 2025-04-28 141757.png

那么定时器的初值 X=65536−N=65536−46080=19456。将这个初值拆分为高 8 位和低 8 位:

  • 高 8 位:TH0=(65536−46080)/256=76(十六进制为 0x4C)
  • 低 8 位:TL0=(65536−46080)%256=160(十六进制为 0xA0)
3. 中断使能
要让定时器溢出时能够触发中断,需要使能定时器中断和全局中断。通过设置相应的中断允许寄存器(如ET0和EA)来实现。

  1. #include <reg51.h>
  2. // 定时器0中断服务程序
  3. void timer0_isr() interrupt 1 {
  4.     // 重新加载初值,以实现每50ms触发一次中断
  5.     TH0 = (65536 - 50000) / 256;
  6.     TL0 = (65536 - 50000) % 256;
  7.     // 其他中断处理代码
  8. }
  9. void main() {
  10.     // 配置定时器0为模式1
  11.     TMOD = 0x01;
  12.     // 加载初值,以实现每50ms触发一次中断
  13.     TH0 = (65536 - 50000) / 256;
  14.     TL0 = (65536 - 50000) % 256;
  15.     // 使能定时器0中断
  16.     ET0 = 1;
  17.     // 使能全局中断
  18.     EA = 1;
  19.     // 启动定时器0
  20.     TR0 = 1;
  21.     while (1) {
  22.         // 主循环可以处理其他任务
  23.     }
  24. }
复制代码
  • TMOD = 0x01;:把定时器 0 设置为模式 1。
  • TH0 = (65536 - 50000) / 256; 和 TL0 = (65536 - 50000) % 256;:计算并加载定时器 0 的初值,以实现每 50ms 触发一次中断。
  • ET0 = 1;:使能定时器 0 中断。
  • EA = 1;:使能全局中断。
  • TR0 = 1;:启动定时器 0。

综上所述,定时器 0 每 50ms 触发一次计数是通过对工作模式、初值以及中断使能等方面进行设置来实现的。





回复

使用道具 举报 送花

已绑定手机

6

主题

167

回帖

600

积分

高级会员

积分
600
 楼主| 发表于 2025-4-28 14:21:46 | 显示全部楼层

程序中对定时器0赋值的50000和计算得出结果46080为什么不一样?


程序中出现赋值的 50000 和计算得出的 46080 不同,主要是因为二者在定时计算里代表的含义有差异,下面为你详细解释。

在代码里 TH0 = (65536 - 50000) / 256; 和 TL0 = (65536 - 50000) % 256; 中的 50000 是假定单片机的晶振频率为 12MHz 时计算得出的结果。
当晶振频率为 12MHz 时,机器周期 屏幕截图 2025-04-28 142424.png


若要实现 50ms 的定时,所需的机器周期数 屏幕截图 2025-04-28 142523.png
由于定时器 0 在模式 1 下是 16 位定时器,其计数范围是 0 - 65535。为了能在计满 50000 个机器周期后产生溢出,就要给定时器赋初值 X=65536−50000。

而 46080 是在晶振频率为 11.0592MHz 时计算得出的。此时机器周期 屏幕截图 2025-04-28 141647.png


要实现 50ms 的定时,所需的机器周期数 屏幕截图 2025-04-28 141757.png
同样,为了在计满约 46080 个机器周期后产生溢出,要给定时器赋初值 X=65536−46080。

总结
*50000 是晶振频率为 12MHz 时,实现 50ms 定时所需的机器周期数。
*46080 是晶振频率为 11.0592MHz 时,实现 50ms 定时所需的机器周期数。
在实际应用中,要依据所使用单片机的晶振频率来正确计算定时器的初值,这样才能确保定时的准确性。若晶振频率是 12MHz,就用 50000 来计算初值;若晶振频率是 11.0592MHz,则用 46080 来计算初值。












回复

使用道具 举报 送花

已绑定手机

6

主题

167

回帖

600

积分

高级会员

积分
600
 楼主| 发表于 2025-4-28 14:38:20 | 显示全部楼层

11.0592M晶振在串口通讯的波特率上是如何体现?如何进行相关计算

在串口通信中,11.0592MHz 晶振能很好地满足常见波特率设置且误差极小,以下为你详细介绍它在波特率上的体现以及相关计算方法。
体现优势的原因
串口通信的波特率是指每秒传输的比特数。在 51 单片机中,波特率通常由定时器溢出率来决定。
11.0592MHz 晶振之所以在串口通信中表现出色,是因为它能让定时器产生的溢出率与常见的标准波特率精确匹配,进而保证数据传输的准确性。

相关计算步骤
1. 明确波特率计算公式
在 51 单片机中,当串口工作在模式 1 或模式 3 时,波特率计算公式如下:
屏幕截图 2025-04-28 143707.png
其中,SMOD 是特殊功能寄存器 PCON 的最高位(位 7),当 SMOD = 0 时,波特率不加倍;当 SMOD = 1 时,波特率加倍。
定时器溢出率的计算公式为:
屏幕截图 2025-04-28 143753.png
这里,fosc​ 是晶振频率,n 是定时器的位数(对于定时器 1 工作在模式 2,n=8),X 是定时器的初值。

2. 以 9600bps 波特率为例计算定时器初值
假设使用定时器 1 工作在模式 2(8 位自动重装模式),SMOD = 0(波特率不加倍),晶振频率 fosc​=11.0592MHz,波特率为 9600bps。
屏幕截图 2025-04-28 144021.png

屏幕截图 2025-04-28 144059.png

3. 代码实现
以下是一个简单的 51 单片机串口初始化代码示例,设置波特率为 9600bps:

  1. #include <reg51.h>
  2. void UART_Init() {
  3.     // 设置定时器 1 工作在模式 2
  4.     TMOD |= 0x20;
  5.     // 加载定时器初值
  6.     TH1 = 0xFD;
  7.     TL1 = 0xFD;
  8.     // 使能定时器 1
  9.     TR1 = 1;
  10.     // 设置串口工作在模式 1
  11.     SCON = 0x50;
  12.     // 波特率不加倍
  13.     PCON &= 0x7F;
  14. }
  15. void main() {
  16.     UART_Init();
  17.     while (1) {
  18.         // 主循环可进行其他操作
  19.     }
  20. }
复制代码
总结

通过上述计算和代码示例可知,使用 11.0592MHz 晶振能够方便地计算出合适的定时器初值,实现常见的标准波特率,保证串口通信的准确性和稳定性。在实际应用中,可根据具体的波特率要求,按照上述步骤计算定时器初值并进行相应的设置。





回复

使用道具 举报 送花

已绑定手机

6

主题

167

回帖

600

积分

高级会员

积分
600
 楼主| 发表于 2025-6-4 21:12:37 | 显示全部楼层
2025.06.04学习了何宾老师 《STC 32G12K128》视频中”第四十七集 定时器与计数器原理和应用-模块功能、工作模式、寄存器组“
通过何宾老师的详细讲解明白了定时器/计数器的工作模式中速度为1T和12T时的计算公式背后的原理及容易混淆的一些概念问题,还有就是影子寄存器的概念。

QQ浏览器截图20250604210348.png
QQ浏览器截图20250604210539.png



回复

使用道具 举报 送花

已绑定手机

6

主题

167

回帖

600

积分

高级会员

积分
600
 楼主| 发表于 2026-4-17 14:03:17 | 显示全部楼层
功能:按下板上按键P3.5后开始闪烁(闪烁时间可在程序中一键修改),放开后P3.5熄灭。在按下P3.5的同时,按P3.3可以调快闪烁频率,按P3.4可以调慢闪烁频率。

1.声明函数
  1. void delay_ms(u8 ms);
  2. void HardwareMarquee(void);
  3. u8 KeyScan(u8 key);
  4. void shanshuo(u8 ms);
  5. u16 flash_speed;
复制代码

2.主函数
  1. void main(void)
  2. {
  3.     P0M1 = 0x00;   P0M0 = 0x00;
  4.     P1M1 = 0x00;   P1M0 = 0x00;
  5.     P2M1 = 0x00;   P2M0 = 0x00;
  6.     P3M1 = 0x00;   P3M0 = 0x00;
  7.     P4M1 = 0x00;   P4M0 = 0x00;
  8.     P5M1 = 0x00;   P5M0 = 0x00;
  9.     P6M1 = 0x00;   P6M0 = 0x00;
  10.     P7M1 = 0x00;   P7M0 = 0x00;
  11.   
  12.     while(1)
  13.     {
  14. HardwareMarquee();
  15.     }
  16. }
复制代码

3.延时函数
  1. void delay_ms(u8 ms)
  2. {
  3.     u16 i;
  4.     do{
  5.         i = MAIN_Fosc / 6000;
  6.         while(--i);   //6T per loop
  7.     }while(--ms);
  8. }
复制代码
4.按键检测+输出指示
  1. void HardwareMarquee(void)
  2. {
  3.     u8 key_sta;
  4.     if(P35 == 0)  // 按下P35 → 允许闪烁
  5.     {
  6.         // ========== P33:加速(延时变小) ==========
  7.         key_sta = KeyScan(P33);
  8.         if(key_sta == 1)  // 短按
  9.         {
  10.             if(flash_speed > 20        ) flash_speed -= 10;
  11.         }
  12.         if(key_sta == 2)  // 长按连续加速
  13.         {
  14.             if(flash_speed > 20) flash_speed -= 5;
  15.         }
  16.                                 if(flash_speed < 30) flash_speed = 30;
  17.         // ========== P34:减速(延时变大) ==========
  18.         key_sta = KeyScan(P34);
  19.         if(key_sta == 1)  // 短按
  20.         {
  21.             if(flash_speed < 250) flash_speed += 10;
  22.         }
  23.         if(key_sta == 2)  // 长按连续减速
  24.         {
  25.             if(flash_speed < 250) flash_speed += 5;
  26.         }
  27.                                 if(flash_speed > 249) flash_speed = 249;
  28.         // 执行闪烁
  29.         shanshuo(flash_speed);
  30.     }
  31.     else
  32.     {
  33.         P25 = 1;  // 不按就灭灯
  34.     }
  35. }
复制代码
5.按键消抖和长按检测
  1. u8 KeyScan(u8 key)
  2. {
  3.     static u16 cnt = 0;
  4.    
  5.     if(key == 0)  // 按键按下
  6.     {
  7.         delay_ms(10);  // 消抖10ms
  8.         if(key == 0)
  9.         {
  10.             cnt++;
  11.             if(cnt >= 15)  // 长按判定:按住150ms
  12.             {
  13.                 return 2;  // 长按
  14.             }
  15.             return 1;      // 短按
  16.         }
  17.     }
  18.     cnt = 0;
  19.     return 0;
  20. }
复制代码
6.闪烁函数
  1. void shanshuo(u8 ms)
  2. {
  3.                 P25=0;
  4.                 delay_ms(ms);
  5.                 P25=1;
  6.                 delay_ms(ms);
  7. }
复制代码


回复

使用道具 举报 送花

已绑定手机

6

主题

167

回帖

600

积分

高级会员

积分
600
 楼主| 发表于 2026-4-24 10:17:38 | 显示全部楼层
2026.04.24
代码实现的功能:按下P33,P2口指示灯向一个方向顺序亮灭循环,按下P35,P2口指示灯向反方向亮灭循环。
遇到的问题:下边代码++计算的时候没有问题,可以正常循环亮灭。但是- -的时候出现了减到0溢出的问题。导致显示不正常。
  1. void        cc(void)
  2. {
  3.                 if(zx==1)
  4.                 {
  5.                         P2 = ~ledNum[ledIndex];        //输出低驱动
  6.                         ledIndex++;
  7.                         if(ledIndex > 7)
  8.                         {
  9.                                         ledIndex = 0;
  10.                         }
  11.                         delay_ms(50);
  12.                         delay_ms(50);
  13.                 }
  14. }
复制代码
  1. void        ccw(void)
  2. {
  3.                 if(fx==1)
  4.                 {
  5.                         P2 = ~ledNum[ledIndex];        //输出低驱动
  6.                         ledIndex--;
  7.                         if(ledIndex < 0)
  8.                         {
  9.                                         ledIndex = 7;
  10.                         }
  11.                         delay_ms(50);
  12.                         delay_ms(50);
  13.                 }
  14. }
复制代码


改后的- -代码
  1. void        ccw(void)
  2. {
  3.                 if(fx==1)
  4.                 {
  5.                         P2 = ~ledNum[ledIndex2];        //输出低驱动
  6.                         ledIndex2--;
  7.                         if(ledIndex2 == 0xFF)
  8.                         {
  9.                                 ledIndex2 = 7;
  10.                         }
  11.                         
  12.                         delay_ms(50);
  13.                         delay_ms(50);
  14.                 }
  15. }
复制代码
当减到0继续减的时候变为了0xff,就出现了溢出的情况,所以在出现0xff时强制把它赋值为7,重新开始。


完整代码:
  1. /*---------------------------------------------------------------------*/
  2. typedef     unsigned char   u8;
  3. typedef     unsigned int    u16;
  4. typedef     unsigned long   u32;
  5. u8 xdata ledIndex;
  6. u8 xdata ledIndex2;
  7. u8 xdata zx;
  8. u8 xdata fx;
  9. u8 code ledNum[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
  10. void  delay_ms(u8 ms);
  11. void        cc(void);
  12. void        ccw(void);
  13. /******************** 主函数 **************************/
  14. void main(void)
  15. {
  16.     P_SW2 |= 0x80;  //扩展寄存器(XFR)访问使能
  17.     P0M1 = 0x30;   P0M0 = 0x30;   //设置P0.4、P0.5为漏极开路(实验箱加了上拉电阻到3.3V)
  18.     P1M1 = 0x30;   P1M0 = 0x30;   //设置P1.4、P1.5为漏极开路(实验箱加了上拉电阻到3.3V)
  19.     P2M1 = 0x3c;   P2M0 = 0x3c;   //设置P2.2~P2.5为漏极开路(实验箱加了上拉电阻到3.3V)
  20.     P3M1 = 0x50;   P3M0 = 0x50;   //设置P3.4、P3.6为漏极开路(实验箱加了上拉电阻到3.3V)
  21.     P4M1 = 0x3c;   P4M0 = 0x3c;   //设置P4.2~P4.5为漏极开路(实验箱加了上拉电阻到3.3V)
  22.     P5M1 = 0x0c;   P5M0 = 0x0c;   //设置P5.2、P5.3为漏极开路(实验箱加了上拉电阻到3.3V)
  23.     P6M1 = 0x00;   P6M0 = 0xff;   //设置为推挽输出
  24.     P7M1 = 0x00;   P7M0 = 0x00;   //设置为准双向口
  25.     ledIndex = 0;
  26.     ledIndex2 = 7;
  27.     zx = 0;
  28.     fx = 0;
  29.    
  30.     while(1)
  31.     {
  32.                         if(P33==0)
  33.                         {delay_ms(20);
  34.                                 if(P33==0)
  35.                                 {zx=1;
  36.                                         fx=0;
  37.                                 }
  38.                         }
  39.                         if(P35==0)
  40.                         {delay_ms(20);
  41.                                 if(P35==0)
  42.                                 {fx=1;
  43.                                         zx=0;
  44.                                 }
  45.                         }
  46.                         if(zx == 1)               cc();
  47.                         if(fx == 1 && zx == 0)    ccw();
  48.     }
  49. }
  50. //========================================================================
  51. // 顺时针
  52. //========================================================================
  53. void        cc(void)
  54. {
  55.                 if(zx==1)
  56.                 {
  57.                         P2 = ~ledNum[ledIndex];        //输出低驱动
  58.                         ledIndex++;
  59.                         if(ledIndex > 7)
  60.                         {
  61.                                         ledIndex = 0;
  62.                         }
  63.                         delay_ms(50);
  64.                         delay_ms(50);
  65.                 }
  66. }
  67. //========================================================================
  68. // 逆时针
  69. //========================================================================
  70. void        ccw(void)
  71. {
  72.                 if(fx==1&&zx==0)
  73.                 {
  74.                         P2 = ~ledNum[ledIndex2];        //输出低驱动
  75.                         ledIndex2--;
  76.                         if(ledIndex2 == 0xFF)
  77.                         {
  78.                                 ledIndex2 = 7;
  79.                         }
  80.                         
  81.                         delay_ms(50);
  82.                         delay_ms(50);
  83.                 }
  84. }
  85. //========================================================================
  86. // 延时函数
  87. //========================================================================
  88. void delay_ms(u8 ms)
  89. {
  90.      u16 i;
  91.      do{
  92.           i = MAIN_Fosc / 10000;
  93.           while(--i);   //10T per loop
  94.      }while(--ms);
  95. }
复制代码

后来又想了一种办法,就是在数组中增加一项,

  1. u8 code ledNum[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
复制代码

改为
  1. u8 code ledNum[]={0xff,0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
复制代码

然后加从1-8,减从8-1,当其为0时实际是0xff,灯灭状态。
回复

使用道具 举报 送花

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2026-11-7 13:06 , Processed in 0.085061 second(s), 78 queries .

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表