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

跟冲哥学习STC32G128K芯片打卡

[复制链接]
  • 打卡等级:以坛为家I
  • 打卡总天数:210
  • 最近打卡:2025-05-05 17:50:21

1

主题

63

回帖

369

积分

中级会员

积分
369
发表于 2024-5-18 20:26:50 | 显示全部楼层
第二十五课 Flash模拟EEPROM


EEPROM的特点是可以随机访问和修改任何一个字节。
Flash属于广义的EEPROM,因为它也是电擦除的ROM。但是为了区别于一般的按字节为单位的擦写的EEPROM,我们都叫它Flash。FLASH如果数据不为0XFF,需要擦除之后才能写入
通常,单片机里的Flash都用于存放运行代码,在运行过程中不能改;EEPROM是用来保存用户数据,运行过程中可以改变,比如我们在程序运行中需要保存密码等参数,就需要存在EEPROM里。

IAP(全称 In Application Programming,即应用编程),和 ISP (全称 In System Programming,即系统编程)可将内部的Flash用于EEPROM,但每次擦除是512kb  一个扇区。


截图202405182020024203.jpg

截图202405182020133768.jpg

截图202405182020442288.jpg

不操作EEPROM时要禁止访问EEPROM  保证数据安全

void DisableEEPROM(void)
{
    IAP_CONTR = 0;          //关闭 IAP 功能
    IAP_CMD = 0;            //清除命令寄存器
    IAP_TRIG = 0;           //清除触发寄存器
    IAP_ADDRE = 0xff;       //将地址设置到非 IAP 区域
    IAP_ADDRH = 0xff;       //将地址设置到非 IAP 区域
    IAP_ADDRL = 0xff;
}

读数据  32位地址 再通过5a和a5触发

char EEPROM_read_n(u32 EE_address)
{
        char dat;
    EA = 0;     //禁止中断

    IAP_CONTR = 0x80; //使能 IAP
    IAP_TPS = Tip_Delay; //设置擦除等待参数 24MHz
    IAP_CMD = 1;  //设置 IAP 读命令

        IAP_ADDRE = (u8)(EE_address >> 16); //送地址高字节(地址需要改变时才需重新送地址)
        IAP_ADDRH = (u8)(EE_address >> 8);  //送地址中字节(地址需要改变时才需重新送地址)
        IAP_ADDRL = (u8)EE_address;         //送地址低字节(地址需要改变时才需重新送地址)
        IAP_TRIG = 0x5a; //写触发命令(0x5a)
        IAP_TRIG = 0xa5; //写触发命令(0xa5)
        _nop_();   //由于STC32G是多级流水线的指令系统,触发命令后建议加4个NOP,保证IAP_DATA的数据完成准备
        _nop_();
        _nop_();
        _nop_();
        dat = IAP_DATA; //读 IAP 数据

    DisableEEPROM();
    EA = 1;     //重新允许中断
        return dat;
}

写入数据


void EEPROM_write_n(u32 EE_address,u8 dat)
{
    EA = 0;     //禁止中断

    IAP_CONTR = 0x80; //使能 IAP
    IAP_TPS = Tip_Delay; //设置擦除等待参数 24MHz
    IAP_CMD = 2;  //设置 IAP 写命令

        IAP_ADDRE = (u8)(EE_address >> 16); //送地址高字节(地址需要改变时才需重新送地址)
        IAP_ADDRH = (u8)(EE_address >> 8);  //送地址中字节(地址需要改变时才需重新送地址)
        IAP_ADDRL = (u8)EE_address;         //送地址低字节(地址需要改变时才需重新送地址)
        IAP_DATA = dat; //写 IAP 数据
        IAP_TRIG = 0x5a; //写触发命令(0x5a)
        IAP_TRIG = 0xa5; //写触发命令(0xa5)
        _nop_();   //由于STC32G是多级流水线的指令系统,触发命令后建议加4个NOP,保证IAP_DATA的数据完成准备
        _nop_();
        _nop_();
        _nop_();

    DisableEEPROM();
    EA = 1;     //重新允许中断
}

按照扇区擦除  地址位扇区起始地址

void EEPROM_SectorErase(u32 EE_address)
{
    EA = 0;     //禁止中断


    IAP_CONTR = 0x80; //使能 IAP
    IAP_TPS = Tip_Delay;     //设置擦除等待参数 24MHz
    IAP_CMD = 3;      //设置 IAP 擦除命令
    IAP_ADDRE = (u8)(EE_address >> 16); //送扇区地址高字节(地址需要改变时才需重新送地址)
    IAP_ADDRH = (u8)(EE_address >> 8);  //送扇区地址中字节(地址需要改变时才需重新送地址)
    IAP_ADDRL = (u8)EE_address;         //送扇区地址低字节(地址需要改变时才需重新送地址)
    IAP_TRIG = 0x5a; //写触发命令(0x5a)
    IAP_TRIG = 0xa5; //写触发命令(0xa5)
    _nop_();   //由于STC32G是多级流水线的指令系统,触发命令后建议加4个NOP,保证IAP_DATA的数据完成准备
    _nop_();
    _nop_();
    _nop_();
    DisableEEPROM();
    EA = 1;     //重新允许中断
}



回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:210
  • 最近打卡:2025-05-05 17:50:21

1

主题

63

回帖

369

积分

中级会员

积分
369
发表于 2024-5-18 21:51:38 | 显示全部楼层
本帖最后由 Rain_Personal 于 2024-5-20 19:34 编辑

第二十六课 DS18b20温度读取

单总线连接模式,需要上拉,对于DS18b20,需要接若上拉电阻 4.7kΩ
截图202405191706481521.jpg

DS18B20的核心功能是它的直接数字温度传感器。温度传感器的精度为用户可编程的9,10,11或12位。温度分辨率分别为0.5℃、0.25℃、0.125℃和0.0625℃。芯片在上电状态下默认的精度为12位。

截图202405191708406138.jpg

使用时操作步骤
截图202405191728041341.jpg

截图202405201932441985.jpg


void DS18b20_Reset(void)                //复位
{
        bit flag = 1;
       
        while( flag )
        {
                DQ = 0;                                //输出低电平
                Delay480us();
                DQ = 1;                                //输出高电平
                Delay60us();
                flag = DQ;                        //读取当前电平
                Delay480us();       
        }               
}

void DS18b20_Write_0(void)                //写逻辑0码
{
        DQ = 0;                                //输出低电平
        Delay60us();
        DQ = 1;                                //输出高电平
        Delay1us();               
        Delay1us();       
}

void DS18b20_Write_1(void)                //写逻辑1码
{
        DQ = 0;                                //输出低电平
        Delay1us();       
        Delay1us();       
        DQ = 1;                                //输出高电平
        Delay60us();       
}


bit DS18b20_Read(void)                //读取电平
{
        bit state ;
       
        DQ = 0;                                //输出低电平
        Delay1us();       
        Delay1us();       
        DQ = 1;                                //输出低电平
        Delay1us();       
        Delay1us();       
        state = DQ;                        //读取当前电平

        Delay60us();

        return         state;
}
// 0XCC  = 1100 1100b & 0x01
void DS18b20_WriteByte(u8 dat)        //写一个字节
{
        u8 i;
        for( i=0;i<8;i++ )                //循环八次
        {
                if( dat & 0x01 )
                        DS18b20_Write_1();
                else
                        DS18b20_Write_0();
                dat >>=1;
        }
}
// 1000 0000
// x100 0000
// xx10 0000
u8 DS18b20_ReadByte(void)                //读取一个字节
{
        u8 i;
        u8 dat=0;
        for( i=0;i<8;i++ )                //循环八次
        {
                dat >>=1;
               
                if( DS18b20_Read() )        //如果读取到的是1,
                        dat |= 0x80;
        }
        return dat;
}

u16 DS18b20_ReadTemp(void)        //读取并且换算温度,并返回
{
        u8 TempH;
        u8 TempL;
        u16 temperture;
       
        DS18b20_Reset();                //1.复位
        DS18b20_WriteByte(0XCC);//2.跳过ROM指令
        DS18b20_WriteByte(0X44);//3.开始转化
        while(!DQ);                                //4.等待DQ变成高电平
       
        DS18b20_Reset();                //5.复位
        DS18b20_WriteByte(0XCC);//6.跳过ROM指令       
        DS18b20_WriteByte(0XBE);//7.读取

        TempL = DS18b20_ReadByte();
        TempH = DS18b20_ReadByte();       
       
        if( TempH & 0XF8 )                                                        //有1出现就是负数
        {
                MinusFlag = 1;                                                        //标志位负数
                temperture = ((TempH<<8) | TempL);                //将温度换算成16位
                temperture = (~temperture) +1;                         //按位取反+1
                temperture = temperture*10*0.0625;                //最终温度保留一位小数
        }
        else
        {
                MinusFlag = 0;                                                        //标志位正数
                temperture = ((TempH<<8) | TempL);                //将温度换算成16位
                temperture = temperture*10*0.0625;                //最终温度保留一位小数
        }
        Temp = temperture;
        return temperture;                                                        //保留一位小数的温度
}


回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:210
  • 最近打卡:2025-05-05 17:50:21

1

主题

63

回帖

369

积分

中级会员

积分
369
发表于 2024-5-21 21:26:21 | 显示全部楼层
第二十七课 软件模拟SPI

SPI是串行外设接口(Serial Peripheral Interface)的缩写。SPI是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便,正是出于这种简单易用的特性,现在越来越多的芯片集成了这种通信协议。

截图202405212056216486.jpg


SPI总线包括4条逻辑线,定义如下:
●MISO:Master input slave output 主机输入,从机输出(数据来自从机);
●MOSI:Master output slave input 主机输出,从机输入(数据来自主机);
●SCLK :Serial Clock 串行时钟信号,由主机产生发送给从机;
●SS:Slave Select 片选信号,由主机发送,以控制与哪个从机通信,通常是低电平有效信号。

截图202405212057271179.jpg


传送数据依靠clock引脚改变引脚电压,提前将0或者1 高低电平写入MOSI或者MISO,通过改变SCLK电平,产生上升沿或者下降沿就可以传输数据给从机或者主机


W25X40CL


CS:低电平有效
DI/DO:数据输入输出端
WP:低电平写保护
HOLD:低电平时暂停
CLK:时钟信号



#define CS                 P22
#define MISO        P24
#define WP                P53
#define MOSI        P23
#define SCLK        P25


void SPI_Init(void)                                //初始化
{
        CS           = 1;                                        //不选中该器件
        MISO  = 1;                                        //       
        WP          = 1;                       
        MOSI  = 1;       
        SCLK  = 0;                                        //spi模式0,sclk初始化为低电平       
}


void SPI_WriteByte(u8 dat)                //写入一个字节
{
        u8 i;
        for( i=0;i<8;i++ )
        {
                if( dat & 0x80 )
                        MOSI = 1;
                else
                        MOSI = 0;
                SCLK = 1;                                //下降沿
                SCLK = 0;
                dat <<=1;
        }
}


u8 SPI_ReadByte(void)                        //读取一个字节
{
        u8 i;
        u8 dat=0;
       
        for( i=0;i<8;i++ )
        {
                dat<<=1;
               
                SCLK = 1;                               
                if( MISO )                                //从机往主机发送数据的引脚
                        dat |= 1;
//                else
//                        dat |= 0;
                SCLK = 0;
        }
       
        return dat;
}



写使能               26h
写失能               04h
读取状态寄存器  05h
写入状态寄存器  01h
读取数据            03h
快速读取            0Bh
双输出快速读取  3Bh
页编程               02h
扇区擦除            20h
32KB块擦除        52h

回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:210
  • 最近打卡:2025-05-05 17:50:21

1

主题

63

回帖

369

积分

中级会员

积分
369
发表于 2024-5-22 21:17:22 | 显示全部楼层
第二十八课 硬件SPI读写Flash芯片

截图202405222035449471.jpg

Flash芯片外接至P2.3和P2.5两个引脚


截图202405222034326512.jpg

截图202405222035353722.jpg

这两个引脚可以复用位P2.3 MOSI_2 和P2.5 SCLK_2。


截图202405222042272571.jpg


void SPI_Init(void)                                //初始化
        {
                P_SW1 &= 0XF3;                //1111 0011                引脚选择
                P_SW1 |= 0X04;                //0000 0100
               
                SPCTL = 0X90;                //模式配置 SSIG = 1   MSTR = 1 设置主机模式
                SPCTL |= 0X40;      //CPOL = 1
               
                SCLK = 0;                        //y引脚初始化
               
                SPIF = 1;                        //清空标志位
                WCOL = 1;
        }
截图202405222043536057.jpg

截图202405222044014021.jpg


        void SPI_WriteByte(u8 dat)                //写入一个字节
        {
                SPDAT = dat;           // 发送数据
                while(SPIF == 0);    // 正在发送数据
                SPIF = 1;               // 清空标志位
                WCOL = 1;
        }


        u8 SPI_ReadByte(void)                        //读取一个字节
        {
                SPDAT = 0XFF;
                while(SPIF == 0);
                SPIF = 1;
                WCOL = 1;               
                return SPDAT;
        }

回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:210
  • 最近打卡:2025-05-05 17:50:21

1

主题

63

回帖

369

积分

中级会员

积分
369
发表于 2024-5-25 17:39:33 | 显示全部楼层
第二十九课 SPI读写Flash芯片




截图202405251717261195.jpg

读取芯片的ID 为 12
截图202405251716007707.jpg


u8 FLASH_CheckID(void)                                //读取ID
{
        u8 id;
        CS = 0;
       
        SPI_WriteByte(0XAB);                //写入读取id命令
       
        SPI_WriteByte(0X00);                //写入空命令
        SPI_WriteByte(0X00);                //写入空命令
        SPI_WriteByte(0X00);                //写入空命令
       
        id = SPI_ReadByte();                //读取命令
       
        CS = 1;
        return id;
}
截图202405251721066409.jpg

当发送90时

SPI_WriteByte(0X90);                //写入读取id命令
                       
SPI_WriteByte(0X00);                //写入空命令
SPI_WriteByte(0X00);                //写入空命令
SPI_WriteByte(0X00);                //写入空命令
                       
MID = SPI_ReadByte();                //读取命令
ID = SPI_ReadByte();                //读取命令

会首先返回制造商id即MID  EF
随后会发送ID 设备ID          12

u8 FLASH_CheckBusy(void)                //读取状态
{
        u8 state;
        CS = 0;
        SPI_WriteByte(0X05);                //写入读取状态命令
        state = SPI_ReadByte();                //读取命令
        CS = 1;
        return state;
}


void FLASH_WriteEnable(void)        //写能使
{
        while(FLASH_CheckBusy()>0);
        CS = 0;
        SPI_WriteByte(0X06);                //写入写使能命令
        CS = 1;
}

void FLASH_Erase(u32 addr)                //扇区擦除
{
        while(FLASH_CheckBusy()>0);
        FLASH_WriteEnable();
       
        CS = 0;
        SPI_WriteByte(0X20);                //写入扇区擦除
       
        SPI_WriteByte((u8)(addr>>16));                //写入地址最高位
        SPI_WriteByte((u8)(addr>>8));                //写入地址
        SPI_WriteByte((u8)(addr>>0));                //写入地址最第位
       
        CS = 1;
}


void FLASH_Read(u32 addr,u8 *buffr,u16 length)                //d扇区读取
{
        u16 i=0;
        while(FLASH_CheckBusy()>0);
       
        CS = 0;
        SPI_WriteByte(0X03);                //写入
       
        SPI_WriteByte((u8)(addr>>16));                //写入地址最高位
        SPI_WriteByte((u8)(addr>>8));                //写入地址
        SPI_WriteByte((u8)(addr>>0));                //写入地址最第位
       
        do
        {
                buffr = SPI_ReadByte();
                i++;
        }while(length--);
       
        CS = 1;
}

void FLASH_Write(u32 addr,u8 *buffr,u16 length)                //d扇区写入
{
        u16 i=0;
        if( length==0 )
                return ;
        while(FLASH_CheckBusy()>0);
        FLASH_WriteEnable();
       
        CS = 0;
        SPI_WriteByte(0X02);                //写入
       
        SPI_WriteByte((u8)(addr>>16));                //写入地址最高位
        SPI_WriteByte((u8)(addr>>8));                //写入地址
        SPI_WriteByte((u8)(addr>>0));                //写入地址最第位
       
        do
        {
                SPI_WriteByte(buffr);
                i++;
                if( addr&0xff==0 )
                        break;
        }while(length--);
        CS = 1;
}

截图202405251653095640.jpg
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:210
  • 最近打卡:2025-05-05 17:50:21

1

主题

63

回帖

369

积分

中级会员

积分
369
发表于 2024-5-26 15:38:50 | 显示全部楼层
第三十课 软件模拟IIC



截图202405261526242856.jpg

IIC总线简单来说就是一根线来控制时钟(SCL)和一个线来发送数据(SDA)。两个线按照一定的传输协议来进行传输数据。由于只有一根线来读写数据,也就意味着同一时间只能有一个发送设备。可以通过地址操作控制与那个iic设备进行通讯。

iic的两条通讯线都需要通过上拉电阻,使空闲电位处于高电位。
主机发送数据的信号控制模式
截图202405261528417501.jpg

首先主设备给总线发送起始信号,和从机地址,随后从机应答,主机发送数据,从机应答。。。最后发送停止信号
截图202405261530133910.jpg

主设备发送起始信号和从机地址,随后从机应答,并传送数据,主机应答,从机再次发送数据,。。。。最后是停止信号

iic的协议需要

1.启动信号
截图202405261532014542.jpg



void IIC_START(void)        //IIC开始
{
        SCL = 1;
        SDA        = 1;
        IIC_DELAY();
        SDA        = 0;
        IIC_DELAY();
        SCL = 0;
        IIC_DELAY();
}

2.等待从机应答信号
截图202405261533088263.jpg


void IIC_WAITACK(void)        //等到从机ACK
{
        SDA        = 1;
        IIC_DELAY();
        SCL = 1;
        IIC_DELAY();
        ack = SDA;
        IIC_DELAY();
        SCL = 0;
        IIC_DELAY();
}

等待iic从机设备将SDA数据引脚电位拉低

3.终止信号

截图202405261534262700.jpg


void IIC_STOP(void)                //IIC结束
{
        SCL = 0;
        SDA        = 0;
        IIC_DELAY();
        SCL = 1;
        IIC_DELAY();
        SDA        = 1;
        IIC_DELAY();
}

4.主机发送ACK信号

截图202405261535015285.jpg

主机将SDA引脚拉低

void IIC_SENDACK(void)        //发送ACK
{
        SDA        = 0;
        IIC_DELAY();
        SCL = 1;
        IIC_DELAY();
        SCL = 0;
        IIC_DELAY();
}


5.主机发送NO_ACK信号

void IIC_SENDNACK(void)        //发送NACK
{
        SDA        = 1;
        IIC_DELAY();
        SCL = 1;
        IIC_DELAY();
        SCL = 0;
        IIC_DELAY();
}


6.发送一个字节
截图202405261536356160.jpg


void IIC_SENDBYTE(u8 dat)        //发送一个字节
{
        u8 i=8;
        do
        {
                if( dat& 0x80 )
                        SDA        = 1;
                else
                        SDA        = 0;
                IIC_DELAY();
                dat<<=1;
                SCL = 1;
                IIC_DELAY();       
                SCL = 0;
                IIC_DELAY();               
        }
        while(--i);
}

7.读取一个字节

截图202405261537491559.jpg


u8 IIC_READBYTE(void)        //读取一个字节
{
        u8 i=8,dat=0;
        SDA        = 1;
        do
        {
                SCL = 1;
                IIC_DELAY();
                dat<<=1;
                if( SDA )
                        dat |= 1;
                SCL = 0;
                IIC_DELAY();
        }
        while(--i);
       
        return dat;
}


回复 支持 反对

使用道具 举报 送花

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

本版积分规则

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

GMT+8, 2025-5-8 03:36 , Processed in 0.113429 second(s), 76 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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