找回密码
 立即注册
楼主: yuyy1989

冲哥32位8051视频学习日记-已看到27集-实验箱到了

[复制链接]
  • 打卡等级:常住居民III
  • 打卡总天数:141
  • 最近打卡:2024-05-24 21:11:31

3

主题

64

回帖

1196

积分

金牌会员

积分
1196
发表于 2023-5-23 08:52:07 | 显示全部楼层
本帖最后由 yuyy1989 于 2023-5-23 11:28 编辑

第23集,看门狗
系统复位,复位的主要作用是把单片机内部的特殊功能寄存器置于初始状态,使单片机硬件、软件从一个确定的、唯一的起点开始工作。
复位方式包括
QQ截图20230523081245.png
看门狗,看门狗是一个计数器,它的基本功能是在软件问题和程序跑偏后重启系统。看门狗正常工作时会自动计数,程序进程会定时将其归零。如果系统在某个地方卡住了或者跑了,定时器就会溢出,是系统强制复位。
软件的可靠性一直是一个关键问题。任何使用软件的人都可能遇到电脑死机或程序失控的问题,这种问题在嵌入式系统中也存在。由于单片机抗干扰能力有限,在工业现场仪器仪表中,经常因电压不稳和电弧干扰而死机。在水表、电表无人值守的情况下,系统因干扰无法重启。为了保证系统在受到干扰后能自动恢复正常,看门狗定时器的使用是非常有价值的。
看门狗实现原理,在系统运行以后也就启动了看门狗的计数器,看门狗就开始自动计数,如果到了一定的时间还不去清理看门狗(也叫喂狗),那么看门狗计数器就会溢出从而引起看门狗中断,造成系统复位。所以,在使用有看门狗的芯片时要注意清理看门狗。
看门狗实验,初始状态P2上的LED全亮,按下P34后开启看门狗,P2上的LED流水灯,按住P35按键1秒后看门狗复位P2上的LED全亮


代码实现

  1. #define MAIN_Fosc       24000000L   //定义主时钟
  2. void delay_ms(uint16_t ms)
  3. {
  4.     uint16_t i;
  5.     do{
  6.         i = MAIN_Fosc / 6000;
  7.         while(--i);   //6T per loop
  8.     }while(--ms);
  9. }
  10. /******************** 主函数 **************************/
  11. void main(void)
  12. {
  13.     uint8_t ledindex = 0;
  14.     WTST = 0;  //设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
  15.     EAXFR = 1; //扩展寄存器(XFR)访问使能
  16.     CKCON = 0; //提高访问XRAM速度
  17.     RSTFLAG |= 0x04;   //设置硬件复位后需要检测P3.2的状态选择运行区域,否则硬件复位后进入USB下载模式
  18.     P0M1 = 0x00;   P0M0 = 0x00;   //设置为准双向口
  19.     P1M1 = 0x00;   P1M0 = 0x00;   //设置为准双向口
  20.     P2M1 = 0x00;   P2M0 = 0x00;   //设置为准双向口
  21.     P3M1 = 0x00;   P3M0 = 0x00;   //设置为准双向口
  22.     P4M1 = 0x00;   P4M0 = 0x00;   //设置为准双向口
  23.     P5M1 = 0x00;   P5M0 = 0x00;   //设置为准双向口
  24.     P6M1 = 0x00;   P6M0 = 0x00;   //设置为准双向口
  25.     P7M1 = 0x00;   P7M0 = 0x00;   //设置为准双向口
  26.     //USB调试及复位所需代码-----
  27.     P3M0 &= ~0x03;
  28.     P3M1 |= 0x03;
  29.     IRC48MCR = 0x80;
  30.     while (!(IRC48MCR & 0x01));
  31.     //如果使用USB-CDC需要下面的两行代码
  32.     // USBCLK = 0x00;
  33.     // USBCON = 0x90;
  34.     //如果使用USB-HID注释掉上面两行代码
  35.     usb_init();
  36.     //-------------------------
  37.    
  38.     EUSB = 1;   //IE2相关的中断位操作使能后,需要重新设置EUSB
  39.     EA = 1;     //打开总中断
  40.     P2 = 0x00; //复位后P2上的LED全部亮起
  41.     while (P34 != 0);
  42.     WDT_CONTR = 0x25; //24M主频下约1.05秒
  43.     while(1)
  44.     {
  45.         if(P35 != 0) //如果P35按键没有按下
  46.         {
  47.             CLR_WDT = 1; //清零看门狗
  48.         }
  49.         delay_ms(100);
  50.         P2 = ~(1<<ledindex);
  51.         ledindex++;
  52.         if(ledindex > 7)
  53.             ledindex = 0;
  54.     }
  55. }
复制代码



回复 支持 反对

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:141
  • 最近打卡:2024-05-24 21:11:31

3

主题

64

回帖

1196

积分

金牌会员

积分
1196
发表于 2023-5-23 16:07:15 | 显示全部楼层
第24集,比较器


核心作用就是通过比较两个电压的大小,来及时的响应某些动作
QQ截图20230523112926.png
QQ截图20230523112942.png

手册里例程的上升沿下降沿的注释标反了
QQ截图20230523155307.png QQ截图20230523155514.png

上升沿时0变1,触发中断后CMPRES为1,下降沿是1变0,触发中断后CMPRES为0

代码示例

  1. #include "stc32g.h"
  2. #include "intrins.h"
  3. void main(void)
  4. {
  5.     WTST = 0;  //设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
  6.     EAXFR = 1; //扩展寄存器(XFR)访问使能
  7.     CKCON = 0; //提高访问XRAM速度
  8.     RSTFLAG |= 0x04;   //设置硬件复位后需要检测P3.2的状态选择运行区域,否则硬件复位后进入USB下载模式
  9.     P0M1 = 0x00;   P0M0 = 0x00;   //设置为准双向口
  10.     P1M1 = 0x00;   P1M0 = 0x00;   //设置为准双向口
  11.     P2M1 = 0x00;   P2M0 = 0x00;   //设置为准双向口
  12.     P3M1 = 0x00;   P3M0 = 0x00;   //设置为准双向口
  13.     P4M1 = 0x00;   P4M0 = 0x00;   //设置为准双向口
  14.     P5M1 = 0x00;   P5M0 = 0x00;   //设置为准双向口
  15.     P6M1 = 0x00;   P6M0 = 0x00;   //设置为准双向口
  16.     P7M1 = 0x00;   P7M0 = 0x00;   //设置为准双向口
  17.     //USB调试及复位所需代码-----
  18.     P3M0 &= ~0x03;
  19.     P3M1 |= 0x03;
  20.     IRC48MCR = 0x80;
  21.     while (!(IRC48MCR & 0x01));
  22.     //如果使用USB-CDC需要下面的两行代码
  23.     // USBCLK = 0x00;
  24.     // USBCON = 0x90;
  25.     //如果使用USB-HID注释掉上面两行代码
  26.     usb_init();
  27.     //-------------------------
  28.     CMPEXCFG |= 0x40; //比较器 DC 迟滞10mv P3.6负极 P3.7正极
  29.     CMPCR1 = 0xB0; //开启比较功能,使能上升沿和下降沿中断
  30.     CMPCR2= 0x00; //使能0.1us模拟滤波
  31.    
  32.     EUSB = 1;   //IE2相关的中断位操作使能后,需要重新设置EUSB
  33.     EA = 1;     //打开总中断
  34.     while(1)
  35.     {
  36.     }
  37. }
  38. void CMP_Isr() interrupt 21
  39. {
  40.     CMPIF = 0; //清中断标志
  41.     if (CMPRES)
  42.     {
  43.         P20 = !P20; //上升沿(0变1)中断测试端口
  44.     }
  45.     else
  46.     {
  47.         P21 = !P21; //下降沿(1变0)中断测试端口
  48.     }
  49. }
复制代码



回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:405
  • 最近打卡:2025-04-16 13:31:35
已绑定手机

5

主题

98

回帖

1938

积分

金牌会员

积分
1938
发表于 2023-5-24 10:37:12 | 显示全部楼层
回复

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:8
  • 最近打卡:2025-04-27 10:40:24

11

主题

425

回帖

1973

积分

版主

积分
1973
发表于 2023-5-24 11:50:18 | 显示全部楼层
【免费+包邮】 送/申样热线:0513-55012928、0513-55012929、0513-55012966
工作时间:  8:30-12:00  13:00-17:30(周一 到 周五, 法定节假日除外),也可加如下 QQ 或 微信 申请
加STC华南区客服刘经理QQ: 3398500488 ;微信:18106296592  要求 【免费+包邮】 送, 还免费教你仿真  
加STC华南区客服曹经理QQ:1933892258 ;微信:18106296595 要求 【免费+包邮】 送, 还免费教你仿真
加STC华东区客服聂经理QQ:2593903262;微信:18106296598  要求 【免费+包邮】 送, 还免费教你仿真
加STC西北区客服孙经理QQ: 1347154513 ;微信:18106296593  要求 【免费+包邮】 送, 还免费教你仿真
加STC华北区客服石经理QQ: 1638975601 ;微信:19952583876  要求 【免费+包邮】 送, 还免费教你仿真
加STC华中区客服唐经理QQ:2571301708 ;微信:18106296589 要求 【免费+包邮】 送, 还免费教你仿真
加STC东北区客服张经理QQ:3141888640 ;微信:19952583265   要求 【免费+包邮】 送, 还免费教你仿真
加STC西南区客服张经理QQ:3141888640 ;微信:19952583265   要求 【免费+包邮】 送, 还免费教你仿真

或者加我QQ:2269694595,我帮您联系对应业务员
QQ:2269694595     微信:18106296594
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:141
  • 最近打卡:2024-05-24 21:11:31

3

主题

64

回帖

1196

积分

金牌会员

积分
1196
发表于 2023-5-26 15:12:07 | 显示全部楼层
第25集,FLASH模拟EEPROM

实验箱还没到,先继续看

FLASH和EEPROM是什么
EEPROM的全称是“电可擦除可编程只读存储器” ,即 Electrically Erasable Programmable Read-Only Memory:是相对于紫外擦除的rom来讲的。但是今天已经存在多种 EEPROM 的变种,变成了一类存储器的统称。
狭义的EEPROM:
这种rom的特点是可以随机访问和修改任何一个字节。这是最传统的一种EEPROM,掉电后数据不丢失,可以保存 100年,可以擦写100w次。具有较高的可靠性,但是电路复杂/成本也高。因此目前的 EEPROM 都是几十千字节到几百千字节的,绝少有超过 512K 的。
Flash:
Flash属于广义的EEPROM,因为它也是电擦除的ROM。但是为了区别于一般的按字节为单位的擦写的EEPROM,我们都叫它Flash。FLASH如果数据不为OXFF,需要擦除之后才能写入

实验:点击P32切换LED亮起,点击P35保存LED状态,重新通电恢复保存的LED状态

运行效果


代码实现
  1. #include "stc32g.h"
  2. #include "intrins.h"
  3. #define MAIN_Fosc       24000000L   //定义主时钟
  4. void delay_ms(uint16_t ms)
  5. {
  6.     uint16_t i;
  7.     do{
  8.         i = MAIN_Fosc / 6000;
  9.         while(--i);   //6T per loop
  10.     }while(--ms);
  11. }
  12. void IapIdle(void)
  13. {
  14.     IAP_CONTR = 0; //关闭 IAP 功能
  15.     IAP_CMD = 0; //清除命令寄存器
  16.     IAP_TRIG = 0; //清除触发寄存器
  17.     IAP_ADDRE = 0x00;
  18.     IAP_ADDRH = 0x00;
  19.     IAP_ADDRL = 0x00;
  20. }
  21. uint8_t IapRead(uint32_t addr)
  22. {
  23.     char dat;
  24.     IAP_CONTR = 0x80; //使能 IAP
  25.     IAP_TPS = 12; //设置等待参数 12MHz
  26.     IAP_CMD = 1; //设置 IAP 读命令
  27.     IAP_ADDRL = addr; //设置 IAP 低地址
  28.     IAP_ADDRH = addr >> 8; //设置 IAP 高地址
  29.     IAP_ADDRE = addr >> 16; //设置 IAP 最高地址
  30.     IAP_TRIG = 0x5a; //写触发命令(0x5a)
  31.     IAP_TRIG = 0xa5; //写触发命令(0xa5)
  32.     _nop_();
  33.     _nop_();
  34.     _nop_();
  35.     _nop_();
  36.     dat = IAP_DATA; //读 IAP 数据
  37.     IapIdle(); //关闭 IAP 功能
  38.     return dat;
  39. }
  40. void IapProgram(uint32_t addr, uint8_t dat)
  41. {
  42.     IAP_CONTR = 0x80; //使能 IAP
  43.     IAP_TPS = 12; //设置等待参数 12MHz
  44.     IAP_CMD = 2; //设置 IAP 写命令
  45.     IAP_ADDRL = addr; //设置 IAP 低地址
  46.     IAP_ADDRH = addr >> 8; //设置 IAP 高地址
  47.     IAP_ADDRE = addr >> 16; //设置 IAP 最高地址
  48.     IAP_DATA = dat; //写 IAP 数据
  49.     IAP_TRIG = 0x5a; //写触发命令(0x5a)
  50.     IAP_TRIG = 0xa5; //写触发命令(0xa5)
  51.     _nop_();
  52.     _nop_();
  53.     _nop_();
  54.     _nop_();
  55.     IapIdle(); //关闭 IAP 功能
  56. }
  57. void IapErase(uint32_t addr)
  58. {
  59.     IAP_CONTR = 0x80; //使能 IAP
  60.     IAP_TPS = 12; //设置等待参数 12MHz
  61.     IAP_CMD = 3; //设置 IAP 擦除命令
  62.     IAP_ADDRL = addr; //设置 IAP 低地址
  63.     IAP_ADDRH = addr >> 8; //设置 IAP 高地址
  64.     IAP_ADDRE = addr >> 16; //设置 IAP 最高地址
  65.     IAP_TRIG = 0x5a; //写触发命令(0x5a)
  66.     IAP_TRIG = 0xa5; //写触发命令(0xa5)
  67.     _nop_();
  68.     _nop_();
  69.     _nop_();
  70.     _nop_(); //
  71.     IapIdle(); //关闭 IAP 功能
  72. }
  73. void main(void)
  74. {
  75.     uint8_t ledindex = 0;
  76.     WTST = 0;  //设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
  77.     EAXFR = 1; //扩展寄存器(XFR)访问使能
  78.     CKCON = 0; //提高访问XRAM速度
  79.     RSTFLAG |= 0x04;   //设置硬件复位后需要检测P3.2的状态选择运行区域,否则硬件复位后进入USB下载模式
  80.     P0M1 = 0x00;   P0M0 = 0x00;   //设置为准双向口
  81.     P1M1 = 0x00;   P1M0 = 0x00;   //设置为准双向口
  82.     P2M1 = 0x00;   P2M0 = 0x00;   //设置为准双向口
  83.     P3M1 = 0x00;   P3M0 = 0x00;   //设置为准双向口
  84.     P4M1 = 0x00;   P4M0 = 0x00;   //设置为准双向口
  85.     P5M1 = 0x00;   P5M0 = 0x00;   //设置为准双向口
  86.     P6M1 = 0x00;   P6M0 = 0x00;   //设置为准双向口
  87.     P7M1 = 0x00;   P7M0 = 0x00;   //设置为准双向口
  88.     //USB调试及复位所需代码-----
  89.     P3M0 &= ~0x03;
  90.     P3M1 |= 0x03;
  91.     IRC48MCR = 0x80;
  92.     while (!(IRC48MCR & 0x01));
  93.     //如果使用USB-CDC需要下面的两行代码
  94.     // USBCLK = 0x00;
  95.     // USBCON = 0x90;
  96.     //如果使用USB-HID注释掉上面两行代码
  97.     usb_init();
  98.     //-------------------------
  99.     ledindex = IapRead(0x0000);
  100.     if(ledindex > 7)
  101.         ledindex = 0;
  102.     P2 = ~(1<<ledindex);
  103.    
  104.     EUSB = 1;   //IE2相关的中断位操作使能后,需要重新设置EUSB
  105.     EA = 1;     //打开总中断
  106.     while(1)
  107.     {
  108.         if(P32 == 0)
  109.         {
  110.             delay_ms(30);
  111.             if(P32 == 0)
  112.             {
  113.                 while(P32 == 0);
  114.                     ledindex += 1;
  115.                 if(ledindex > 7)
  116.                 ledindex = 0;
  117.                 P2 = ~(1<<ledindex);
  118.             }
  119.         }
  120.         if(P35 == 0)
  121.         {
  122.             delay_ms(30);
  123.             if(P35 == 0)
  124.             {
  125.                 while(P35 == 0);
  126.                 IapErase(0x0000);
  127.                 IapProgram(0x0000,ledindex);
  128.             }
  129.         }
  130.     }
  131. }
复制代码


回复 支持 反对

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:141
  • 最近打卡:2024-05-24 21:11:31

3

主题

64

回帖

1196

积分

金牌会员

积分
1196
发表于 2023-5-27 21:54:54 | 显示全部楼层
用实验箱验证了一下之前写的数码管驱动程序,看来可以正常运行

微信图片_20230527215210.jpg



回复 支持 反对

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:141
  • 最近打卡:2024-05-24 21:11:31

3

主题

64

回帖

1196

积分

金牌会员

积分
1196
发表于 2023-5-29 21:04:45 | 显示全部楼层
验证了一下之前普通按键、矩阵按键、ADC按键都放到一个文件里的程序,功能正常

数码管第1位数是按键类型0普通按键 1矩阵按键 2ADC按键,第2位是按键编号,第3位是按键动作1按键按下 2松开


点评

楼主学习精神值得称赞,希望能配合STC32G12K128实验箱9.6版,分享更多学习经验哦  详情 回复 发表于 2023-5-30 09:17
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:8
  • 最近打卡:2025-04-27 10:40:24

11

主题

425

回帖

1973

积分

版主

积分
1973
发表于 2023-5-30 09:17:25 | 显示全部楼层
yuyy*** 发表于 2023-5-29 21:04
验证了一下之前普通按键、矩阵按键、ADC按键都放到一个文件里的程序,功能正常

数码管第1位数是按键类型0 ...

楼主学习精神值得称赞,希望能配合STC32G12K128实验箱9.6版,分享更多学习经验哦
QQ:2269694595     微信:18106296594
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:141
  • 最近打卡:2024-05-24 21:11:31

3

主题

64

回帖

1196

积分

金牌会员

积分
1196
发表于 2023-5-30 21:33:42 | 显示全部楼层
第26集,DS18B20温度传感器
DS18B20是常用的数字温度传感器,其输出的是数字信号,仅需要一根数据线就能通讯
微信图片_20230530212156.jpg

演示代码
  1. #define DP P33
  2. uint8_t yuyy_ds18b20_reset(void)
  3. {
  4.     uint8_t flag;
  5.     DP = 0;
  6.     yuyy_delay_us(480);
  7.     DP = 1;
  8.     yuyy_delay_us(60);
  9.     flag = DP;
  10.     yuyy_delay_us(420);
  11.     return flag;
  12. }
  13. void yuyy_ds18b20_write0(void)
  14. {
  15.     DP = 0;
  16.     yuyy_delay_us(60);
  17.     DP = 1;
  18.     yuyy_delay_us(2);
  19. }
  20. void yuyy_ds18b20_write1(void)
  21. {
  22.     DP = 0;
  23.     yuyy_delay_us(2);
  24.     DP = 1;
  25.     yuyy_delay_us(60);
  26. }
  27. void yuyy_ds18b20_writebyte(uint8_t dat)
  28. {
  29.     uint8_t i = 0;
  30.     while (i<8)
  31.     {
  32.         if(dat & 0x01)
  33.             yuyy_ds18b20_write1();
  34.         else
  35.             yuyy_ds18b20_write0();
  36.         dat >>= 1;
  37.         i++;
  38.     }
  39.    
  40. }
  41. uint8_t yuyy_ds18b20_readbyte(void)
  42. {
  43.     uint8_t i = 0,dat = 0;
  44.     while (i<8)
  45.     {
  46.         dat >>= 1;
  47.         DP = 0;
  48.         yuyy_delay_us(2);
  49.         DP = 1;
  50.         yuyy_delay_us(2);
  51.         if(DP)
  52.             dat |= 0x80;
  53.         else
  54.             dat &= 0x7F;
  55.         yuyy_delay_us(60);
  56.         i++;
  57.     }
  58.     return dat;
  59. }
  60. float yuyy_ds18b20_readtemp(void)
  61. {
  62.     float temp = -999;
  63.     uint8_t err = 0,th,tl,retry = 0;
  64.     err = yuyy_ds18b20_reset();           //复位
  65.     while (err && retry < 5)
  66.     {
  67.         err = yuyy_ds18b20_reset();
  68.         retry++;
  69.     }
  70.    
  71.     if(err == 0)
  72.     {
  73.         yuyy_ds18b20_writebyte(0xCC);   //跳过ROM指令
  74.         yuyy_ds18b20_writebyte(0x44);   //开始转化
  75.         while (DP == 0);
  76.         yuyy_ds18b20_reset();           //复位
  77.         yuyy_ds18b20_writebyte(0xCC);   //跳过ROM指令
  78.         yuyy_ds18b20_writebyte(0xBE);   //读取
  79.         tl = yuyy_ds18b20_readbyte();
  80.         th = yuyy_ds18b20_readbyte();
  81.         temp = ((int16_t)((th<<8) | tl)) * 0.0625;
  82.     }
  83.     return temp;
  84. }
  85. void test_showsegled(void)
  86. {
  87.     yuyy_segled_show();
  88. }
  89. /******************** 主函数 **************************/
  90. void main(void)
  91. {
  92.     uint16_t num1 = 200;
  93.     float temp = 0;
  94.     WTST = 0;  //设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
  95.     EAXFR = 1; //扩展寄存器(XFR)访问使能
  96.     CKCON = 0; //提高访问XRAM速度
  97.     RSTFLAG |= 0x04;   //设置硬件复位后需要检测P3.2的状态选择运行区域,否则硬件复位后进入USB下载模式
  98.     P0M1 = 0x00;   P0M0 = 0x00;   //设置为准双向口
  99.     P1M1 = 0x00;   P1M0 = 0x00;   //设置为准双向口
  100.     P2M1 = 0x00;   P2M0 = 0x00;   //设置为准双向口
  101.     P3M1 = 0x00;   P3M0 = 0x00;   //设置为准双向口
  102.     P4M1 = 0x00;   P4M0 = 0x00;   //设置为准双向口
  103.     P5M1 = 0x00;   P5M0 = 0x00;   //设置为准双向口
  104.     P6M1 = 0x00;   P6M0 = 0x00;   //设置为准双向口
  105.     P7M1 = 0x00;   P7M0 = 0x00;   //设置为准双向口
  106.     //USB调试及复位所需代码-----
  107.     P3M0 &= ~0x03;
  108.     P3M1 |= 0x03;
  109.     IRC48MCR = 0x80;
  110.     while (!(IRC48MCR & 0x01));
  111.     //如果使用USB-CDC需要下面的两行代码
  112.     // USBCLK = 0x00;
  113.     // USBCON = 0x90;
  114.     //如果使用USB-HID注释掉上面两行代码
  115.     usb_init();
  116.     //-------------------------
  117.     yuyy_timer0init(1000,test_showsegled);
  118.     EUSB = 1;   //IE2相关的中断位操作使能后,需要重新设置EUSB
  119.     EA = 1;     //打开总中断
  120.    
  121.     while(1)
  122.     {
  123.         delay_ms(1);
  124.         if(num1 < 200)
  125.         {
  126.             num1++;
  127.         }
  128.         else
  129.         {
  130.             num1 = 0;
  131.             temp = yuyy_ds18b20_readtemp();
  132.             yuyy_segled_shwowfloatnums(temp,0xFF,2,0);
  133.         }
  134.     }
  135. }
复制代码


回复 支持 反对

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:141
  • 最近打卡:2024-05-24 21:11:31

3

主题

64

回帖

1196

积分

金牌会员

积分
1196
发表于 2023-6-1 21:48:24 | 显示全部楼层
第27集,软件模拟SPI
SPI是串行外设接口(Serial Peripheral Interface)的缩写。SPI,是一种高速的,全双工,同步的通信总线。
一般使用4条线:串行时钟线(SCLK)、主机输入/从机输出数据线MISO、主机输出/从机输入数据线MOSI和低电平有效的从机选择线NSS。
模拟SPI读取flash的id
实验箱原理图上标的flash是pm25lv040
QQ截图20230601210216.png

但我这个实际上是gd25q40ctig,查看这个flash的spi协议,数据在第一个时钟边沿采样,第二个边沿修改
QQ截图20230601210149.png

读取ID的命令,和对应的ID
QQ图片20230601214547.png

QQ截图20230601214126.png

程序读取结果
QQ截图20230601211136.png

代码实现
  1. typedef enum
  2. {
  3.     YUYY_SOFT_SPI_MSB = 0,
  4.     YUYY_SOFT_SPI_LSB
  5. } Yuyy_Soft_Spi_Data_Type;
  6. typedef enum
  7. {
  8.     YUYY_SOFT_SPI_C1S2 = 0, //第一个边沿修改数据,第2个边沿采样
  9.     YUYY_SOFT_SPI_C2S1
  10. } Yuyy_Soft_Spi_Data_Sample_Type;
  11. typedef enum
  12. {
  13.     YUYY_SOFT_SPI_SCK_IDLE_LOW = 0,
  14.     YUYY_SOFT_SPI_SCK_IDLE_HIGH
  15. } Yuyy_Soft_Spi_Sck_Idle_Type;
  16. #define SOFT_SPI_CS P22
  17. #define SOFT_SPI_SCK P25
  18. #define SOFT_SPI_MOSI P23
  19. #define SOFT_SPI_MISO P24
  20. Yuyy_Soft_Spi_Data_Type spi_dt;
  21. Yuyy_Soft_Spi_Data_Sample_Type spi_cpha;
  22. Yuyy_Soft_Spi_Sck_Idle_Type spi_cpol;
  23. void yuyy_soft_spi_delay()
  24. {
  25.     uint8_t i = 3;
  26.     while(i--);
  27. }
  28. void yuyy_soft_spi_init(Yuyy_Soft_Spi_Data_Type dt,Yuyy_Soft_Spi_Data_Sample_Type cpha,Yuyy_Soft_Spi_Sck_Idle_Type cpol)
  29. {
  30.     SOFT_SPI_CS = 1;
  31.     spi_dt = dt;
  32.     spi_cpha = cpha;
  33.     spi_cpol = cpol;
  34.     if(spi_cpol == YUYY_SOFT_SPI_SCK_IDLE_HIGH)
  35.         SOFT_SPI_SCK = 1;
  36.     else
  37.         SOFT_SPI_SCK = 0;
  38.     SOFT_SPI_MISO = 1;
  39.     SOFT_SPI_MOSI = 1;
  40. }
  41. void yuyy_soft_spi_cs(uint8_t lev)
  42. {
  43.     SOFT_SPI_CS = lev;
  44.     yuyy_soft_spi_delay();
  45. }
  46. void yuyy_soft_spi_write_byte(uint8_t dat)
  47. {
  48.     uint8_t i = 0;
  49.     while(i<8)
  50.     {
  51.         if(spi_cpha == YUYY_SOFT_SPI_C1S2)
  52.         {
  53.             SOFT_SPI_SCK = (spi_cpol == YUYY_SOFT_SPI_SCK_IDLE_HIGH ? 0 : 1);
  54.         }
  55.         if(spi_dt == YUYY_SOFT_SPI_MSB)
  56.         {
  57.             if(dat & 0x80)
  58.                 SOFT_SPI_MOSI = 1;
  59.             else
  60.                 SOFT_SPI_MOSI = 0;
  61.             dat <<= 1;
  62.         }
  63.         else
  64.         {
  65.             if(dat & 0x01)
  66.                 SOFT_SPI_MOSI = 1;
  67.             else
  68.                 SOFT_SPI_MOSI = 0;
  69.             dat >>= 1;
  70.         }
  71.         if(spi_cpha == YUYY_SOFT_SPI_C2S1)
  72.         {
  73.             SOFT_SPI_SCK = (spi_cpol == YUYY_SOFT_SPI_SCK_IDLE_HIGH ? 0 : 1);
  74.         }
  75.         yuyy_soft_spi_delay();
  76.         SOFT_SPI_SCK = (spi_cpol == YUYY_SOFT_SPI_SCK_IDLE_HIGH ? 1 : 0);
  77.         i++;
  78.     }
  79. }
  80. uint8_t yuyy_soft_spi_read_byte()
  81. {
  82.     uint8_t i = 0,dat = 0;
  83.     while(i<8)
  84.     {
  85.         if(spi_cpha == YUYY_SOFT_SPI_C2S1)
  86.         {
  87.             SOFT_SPI_SCK = (spi_cpol == YUYY_SOFT_SPI_SCK_IDLE_HIGH ? 0 : 1);
  88.         }
  89.         if(spi_dt == YUYY_SOFT_SPI_MSB)
  90.         {
  91.             dat <<= 1;
  92.             if(SOFT_SPI_MISO)
  93.                 dat |= 0x01;
  94.             else
  95.                 dat &= 0xFE;
  96.         }
  97.         else
  98.         {
  99.             dat >>= 1;
  100.             if(SOFT_SPI_MISO)
  101.                 dat |= 0x80;
  102.             else
  103.                 dat &= 0x7F;
  104.         }
  105.         if(spi_cpha == YUYY_SOFT_SPI_C1S2)
  106.         {
  107.             SOFT_SPI_SCK = (spi_cpol == YUYY_SOFT_SPI_SCK_IDLE_HIGH ? 0 : 1);
  108.         }
  109.         yuyy_soft_spi_delay();
  110.         SOFT_SPI_SCK = (spi_cpol == YUYY_SOFT_SPI_SCK_IDLE_HIGH ? 1 : 0);
  111.         i++;
  112.     }
  113.     return dat;
  114. }
  115. void main(void)
  116. {
  117.     uint8_t id1,id2,id3;
  118.     WTST = 0;  //设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
  119.     EAXFR = 1; //扩展寄存器(XFR)访问使能
  120.     CKCON = 0; //提高访问XRAM速度
  121.     RSTFLAG |= 0x04;   //设置硬件复位后需要检测P3.2的状态选择运行区域,否则硬件复位后进入USB下载模式
  122.     P0M1 = 0x00;   P0M0 = 0x00;   //设置为准双向口
  123.     P1M1 = 0x00;   P1M0 = 0x00;   //设置为准双向口
  124.     P2M1 = 0x00;   P2M0 = 0x00;   //设置为准双向口
  125.     P3M1 = 0x00;   P3M0 = 0x00;   //设置为准双向口
  126.     P4M1 = 0x00;   P4M0 = 0x00;   //设置为准双向口
  127.     P5M1 = 0x00;   P5M0 = 0x00;   //设置为准双向口
  128.     P6M1 = 0x00;   P6M0 = 0x00;   //设置为准双向口
  129.     P7M1 = 0x00;   P7M0 = 0x00;   //设置为准双向口
  130.     //USB调试及复位所需代码-----
  131.     P3M0 &= ~0x03;
  132.     P3M1 |= 0x03;
  133.     IRC48MCR = 0x80;
  134.     while (!(IRC48MCR & 0x01));
  135.     //如果使用USB-CDC需要下面的两行代码
  136.     // USBCLK = 0x00;
  137.     // USBCON = 0x90;
  138.     //如果使用USB-HID注释掉上面两行代码
  139.     usb_init();
  140.     //-------------------------
  141.     yuyy_soft_spi_init(YUYY_SOFT_SPI_MSB,YUYY_SOFT_SPI_C2S1,YUYY_SOFT_SPI_SCK_IDLE_HIGH);
  142.     EUSB = 1;   //IE2相关的中断位操作使能后,需要重新设置EUSB
  143.     EA = 1;     //打开总中断
  144.     while (P32 != 0);
  145.     yuyy_soft_spi_cs(0);
  146.     yuyy_soft_spi_write_byte(0xAB);
  147.     yuyy_soft_spi_write_byte(0x00);
  148.     yuyy_soft_spi_write_byte(0x00);
  149.     yuyy_soft_spi_write_byte(0x00);
  150.     id1 = yuyy_soft_spi_read_byte();
  151.     yuyy_soft_spi_cs(1);
  152.     printf_hid("发送命令0xAB 读取到ID:0x%02X\r\n",id1);
  153.     delay_ms(100);
  154.     yuyy_soft_spi_cs(0);
  155.     yuyy_soft_spi_write_byte(0x90);
  156.     yuyy_soft_spi_write_byte(0x00);
  157.     yuyy_soft_spi_write_byte(0x00);
  158.     yuyy_soft_spi_write_byte(0x00);
  159.     id1 = yuyy_soft_spi_read_byte();
  160.     id2 = yuyy_soft_spi_read_byte();
  161.     yuyy_soft_spi_cs(1);
  162.     printf_hid("发送命令0x90 读取到ID:0x%02X 0x%02X\r\n",id1,id2);
  163.     delay_ms(100);
  164.     yuyy_soft_spi_cs(0);
  165.     yuyy_soft_spi_write_byte(0x9F);
  166.     id1 = yuyy_soft_spi_read_byte();
  167.     id2 = yuyy_soft_spi_read_byte();
  168.     id3 = yuyy_soft_spi_read_byte();
  169.     yuyy_soft_spi_cs(1);
  170.     printf_hid("发送命令0x9F 读取到ID:0x%02X 0x%02X 0x%02X\r\n",id1,id2,id3);
  171.     delay_ms(100);
  172.    
  173.     while(1)
  174.     {
  175.     }
  176. }
复制代码


回复 支持 反对

使用道具 举报 送花

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

本版积分规则

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

GMT+8, 2025-5-7 05:53 , Processed in 0.147104 second(s), 118 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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