文章目录

  • 1、理论基础
    • 1.1、物理层特点
    • 1.2、通信过程
    • 1.3、IIC架构
  • 2、工程建立(硬件iic)
    • 2.1、配置步骤
    • 2.2、cubemx具体配置
  • 3、应用(软件iic)
    • 3.1、原理图
    • 3.2、端口模式+位带操作
    • 3.3、iic头文件
    • 3.4、iic具体实现
    • 3.5、AT24C02读写驱动
  • 4、利用iic拓展io
    • 4.1、原理图
    • 4.2、代码

IO拓展件:PCF8574T
开发板:STM32F429
参考:
1、[正点原子]《STM32F429 开发指南(HAL 库版)》
2、STM32CubeMX使用之I2C通讯

1、理论基础

1.1、物理层特点

  • “总线”指多个设备共用的信号线。在I2C 通讯总线中,支持多个主机及多个从机
  • 一个 I2C 有两条总线, 数据线 (SDA) 用来表示数据,时钟线 (SCL)用于数据收发同步。
  • 每个连接到总线的设备都有一个独立的地址
    从机地址可以是 7位或 10 位
  • 总线通过上拉电阻接到电源。
    当 I2C 设备空闲时,会输出高阻态,当所有设备都空闲时,由上拉电阻把总线拉成高电平
  • 具有仲裁机制 (开漏输出:线与,低电平有效)
    多个主机同时使用总线时,为了防止数据冲突,会利用仲裁方式决定由哪个设备占用总线
  • 三种传输模式
    标准模式传输速率为 100kbit/s ,快速模式为 400kbit/s ,高速模式下可达 3.4Mbit/s
  • 连接到相同总线的 IC 数量受到总线的最大电容 400pF 限制
  • 主机Master 从机Slave

1.2、通信过程

1.2.1、通讯起始和停止信号

  • 空闲时 sda和scl都是高电平
  • 起始位s 停止位p

1.2.2、有效数据

  • scl为高电平时数据有效
  • 每次数据传输都以字节为单位,每次传输的字节数不受限制
  • scl 1 sda 1 表示1
  • scl 1 sda 0 表示0


1.2.3、读写过程

  • 主机写数据到从机 (应答ACK)
    DATA数据包的大小为 8 位

  • 从机写数据到主机


主机等待从机的应答

1.3、IIC架构

  • 数据寄存器 DR
  • 地址寄存器OAR1
  • 第二地址寄存器OAR2
  • 校验寄存器PEC
  • 控制寄存器CR1/2
  • 状态寄存器SR1/2
  • 控制寄存器CCR

2、工程建立(硬件iic)

ST公司实现了硬件的iic,但据说用着不方便,可以参考第3节软件实现

2.1、配置步骤

  • RCC
    设置外部晶振、PLL、主频
  • 调试口
    选择调试模式,选择调试IO口
  • IO分配
    打开相应外设开关
  • IIC参数
    设置速率、地址、主从、时序

2.2、cubemx具体配置

  • 选择开漏模式(一般只有这个选项)

  • 参数设置

3、应用(软件iic)

  • 利用EEPROM 24C02 测试
  • 这里先用标准库

3.1、原理图

3.2、端口模式+位带操作

端口模式设置
GPIO 端口模式寄存器 (GPIOx_MODER) (x = A…I)

  • 3(二进制11),将11左移10位,取反再与,使MODER5的10、11位寄存器清零
    0左移10位,使配置位10为0;即配置端口5为输入模式
    1左移10位,即配置位10为1;即配置端口5为输出模式
#define SDA_IN()  {GPIOH->MODER&=~(3<<(5*2));GPIOH->MODER|=0<<5*2;}  //PH5输入模式
#define SDA_OUT() {GPIOH->MODER&=~(3<<(5*2));GPIOH->MODER|=1<<5*2;} //PH5输出模式

位带操作
stm32之bit-band(位带)操作

3.3、iic头文件

  • 代码均来自正点原子,只是改了一点点
#ifndef _MYIIC_H
#define _MYIIC_H#include "main.h"
#include "stm32f4xx_hal_gpio.h"//IO口位带操作
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2))
#define MEM_ADDR(addr)  *((volatile unsigned long  *)(addr))
#define BIT_ADDR(addr, bitnum)   MEM_ADDR(BITBAND(addr, bitnum)) //IO方向设置
#define SDA_IN()  {GPIOH->MODER&=~(3<<(5*2));GPIOH->MODER|=0<<5*2;} //PH5输入模式
#define SDA_OUT() {GPIOH->MODER&=~(3<<(5*2));GPIOH->MODER|=1<<5*2;} //PH5输出模式//IO口地址映射
#define GPIOH_ODR_Addr    (GPIOH_BASE+20) //0x40021C14
#define GPIOH_IDR_Addr    (GPIOH_BASE+16) //0x40021C10 //IO操作
#define PHout(n)   BIT_ADDR(GPIOH_ODR_Addr,n)  //输出 gpio_writepin
#define PHin(n)    BIT_ADDR(GPIOH_IDR_Addr,n)  //输入 gpio_readpin#define IIC_SCL   PHout(4) //SCL
#define IIC_SDA   PHout(5) //SDA
#define READ_SDA  PHin(5)  //输入SDA  #define CPU_FREQUENCY_MHZ    180        // STM32时钟主频 用于微秒级延时typedef unsigned          char u8;
typedef unsigned short     int u16;
typedef unsigned           int u32;//IIC所有操作函数
void IIC_Init(void);                //初始化IIC的IO口
void IIC_Start(void);               //发送IIC开始信号
void IIC_Stop(void);                //发送IIC停止信号
void IIC_Send_Byte(u8 txd);         //IIC发送一个字节
u8 IIC_Read_Byte(unsigned char ack);//IIC读取一个字节
u8 IIC_Wait_Ack(void);              //IIC等待ACK信号
void IIC_Ack(void);                 //IIC发送ACK信号
void IIC_NAck(void);                //IIC不发送ACK信号void delay_us(uint32_t delay); //hal库 没有微秒延时,需要自己写
void delay_ms(uint32_t ms);#endif

3.4、iic具体实现

  • 为了配合AT24C02的使用,具体的设置可能和其他教程有所差别
#include "myiic.h"//IIC初始化
void IIC_Init(void)
{GPIO_InitTypeDef GPIO_Initure;__HAL_RCC_GPIOH_CLK_ENABLE();   //使能GPIOH时钟//PH4,5初始化设置GPIO_Initure.Pin=GPIO_PIN_4|GPIO_PIN_5;GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP;  //推挽输出GPIO_Initure.Pull=GPIO_PULLUP;          //上拉GPIO_Initure.Speed=GPIO_SPEED_FREQ_HIGH;     //快速HAL_GPIO_Init(GPIOH,&GPIO_Initure);//都拉高表示iic空闲IIC_SDA=1;IIC_SCL=1;
}//产生IIC起始信号:scl 拉高 sda产生下降沿
void IIC_Start(void)
{SDA_OUT();     //配置sda线为输出模式IIC_SDA=1;          IIC_SCL=1;delay_us(4);IIC_SDA=0;//产生下降沿delay_us(4);IIC_SCL=0;//钳住I2C总线,准备发送或接收数据
}//产生IIC停止信号:scl 拉高 sda产生上升沿
void IIC_Stop(void)
{SDA_OUT();//sda线输出IIC_SCL=0;//拉低用于sda高低电平变换IIC_SDA=0;delay_us(4);IIC_SCL=1; delay_us(4);            IIC_SDA=1;//产生上升沿}//等待应答信号到来
//返回值:1,接收应答失败
//        0,接收应答成功
u8 IIC_Wait_Ack(void)
{u8 ucErrTime=0;SDA_IN();      //SDA设置为输入  IIC_SDA=1;delay_us(1);    IIC_SCL=1;delay_us(1);  while(READ_SDA)//sda为低表示应答信号{ucErrTime++;if(ucErrTime>250){IIC_Stop();return 1;}}IIC_SCL=0;      return 0;
} //产生ACK应答(这里我还没弄清楚)
void IIC_Ack(void)
{IIC_SCL=0;SDA_OUT();IIC_SDA=0;delay_us(2);IIC_SCL=1;delay_us(2);IIC_SCL=0;
}//不产生ACK应答
void IIC_NAck(void)
{IIC_SCL=0;SDA_OUT();IIC_SDA=1;delay_us(2);IIC_SCL=1;delay_us(2);IIC_SCL=0;
}       //IIC发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答
void IIC_Send_Byte(u8 txd)
{                        u8 t;   SDA_OUT();         IIC_SCL=0;//拉低时钟开始数据传输for(t=0;t<8;t++)//一位一位的发{              IIC_SDA=(txd&0x80)>>7;//发送txd的最高位txd<<=1;       delay_us(2);   //对TEA5767这三个延时都是必须的IIC_SCL=1;delay_us(2); IIC_SCL=0;    //拉低时钟,变化sdadelay_us(2);}
}       //读1个字节,ack=1时,发送ACK,ack=0,发送nACK
u8 IIC_Read_Byte(unsigned char ack)
{unsigned char i,receive=0;//uint8_tSDA_IN();//SDA设置为输入for(i=0;i<8;i++ ){IIC_SCL=0; delay_us(2);IIC_SCL=1;receive<<=1;if(READ_SDA){receive++;   }delay_us(1); }                    if (!ack)IIC_NAck();//发送nACKelseIIC_Ack(); //发送ACK   return receive;
}void delay_us(uint32_t delay)
{int last, curr, val;int temp;while (delay != 0){temp = delay > 900 ? 900 : delay;last = SysTick->VAL;curr = last - CPU_FREQUENCY_MHZ * temp;if (curr >= 0){do{val = SysTick->VAL;}while ((val < last) && (val >= curr));}else{curr += CPU_FREQUENCY_MHZ * 1000;do{val = SysTick->VAL;}while ((val <= last) || (val > curr));}delay -= temp;}
}void delay_ms(uint32_t ms){for(int i=0;i<ms;i++){delay_us(1000);}
}

3.5、AT24C02读写驱动

  • 头文件
#ifndef _24CXX_H
#define _24CXX_H
#include "myiic.h"#define AT24C01     127
#define AT24C02     255
#define AT24C04     511
#define AT24C08     1023
#define AT24C16     2047
#define AT24C32     4095
#define AT24C64   8191
#define AT24C128    16383
#define AT24C256    32767
//STM32F429开发板使用的是24c02,所以定义EE_TYPE为AT24C02
#define EE_TYPE AT24C02u8 AT24CXX_ReadOneByte(u16 ReadAddr);                            //指定地址读取一个字节
void AT24CXX_WriteOneByte(u16 WriteAddr,u8 DataToWrite);        //指定地址写入一个字节
void AT24CXX_WriteLenByte(u16 WriteAddr,u32 DataToWrite,u8 Len);//指定地址开始写入指定长度的数据
u32 AT24CXX_ReadLenByte(u16 ReadAddr,u8 Len);                   //指定地址开始读取指定长度数据
void AT24CXX_Write(u16 WriteAddr,u8 *pBuffer,u16 NumToWrite);   //从指定地址开始写入指定长度的数据
void AT24CXX_Read(u16 ReadAddr,u8 *pBuffer,u16 NumToRead);      //从指定地址开始读出指定长度的数据u8 AT24CXX_Check(void);  //检查器件
void AT24CXX_Init(void); //初始化IIC
#endif
  • 具体实现
#include "24cxx.h"//初始化IIC接口
void AT24CXX_Init(void)
{IIC_Init();//IIC初始化
}
//在AT24CXX指定地址读出一个数据
//ReadAddr:开始读数的地址
//返回值  :读到的数据
u8 AT24CXX_ReadOneByte(u16 ReadAddr)
{                 u8 temp=0;                                                                                IIC_Start();  if(EE_TYPE>AT24C16){IIC_Send_Byte(0XA0);     //发送写命令IIC_Wait_Ack();IIC_Send_Byte(ReadAddr>>8);//发送高地址       }else IIC_Send_Byte(0XA0+((ReadAddr/256)<<1));   //发送器件地址0XA0,写数据       IIC_Wait_Ack(); IIC_Send_Byte(ReadAddr%256);   //发送低地址IIC_Wait_Ack();        IIC_Start();           IIC_Send_Byte(0XA1);           //进入接收模式             IIC_Wait_Ack();   temp=IIC_Read_Byte(0);           IIC_Stop();//产生一个停止条件        return temp;
}
//在AT24CXX指定地址写入一个数据
//WriteAddr  :写入数据的目的地址
//DataToWrite:要写入的数据
void AT24CXX_WriteOneByte(u16 WriteAddr,u8 DataToWrite)
{                                                                                            IIC_Start();  if(EE_TYPE>AT24C16){IIC_Send_Byte(0XA0);      //发送写命令IIC_Wait_Ack();IIC_Send_Byte(WriteAddr>>8);//发送高地址   }else IIC_Send_Byte(0xA0+((WriteAddr/256)<<1));   //发送器件地址0XA0,写数据      IIC_Wait_Ack();       IIC_Send_Byte(WriteAddr%256);   //发送低地址IIC_Wait_Ack();                                                      IIC_Send_Byte(DataToWrite);     //发送字节                              IIC_Wait_Ack();                     IIC_Stop();//产生一个停止条件 delay_ms(10);
}//在AT24CXX里面的指定地址开始写入长度为Len的数据
//该函数用于写入16bit或者32bit的数据.
//WriteAddr  :开始写入的地址
//DataToWrite:数据数组首地址
//Len        :要写入数据的长度2,4
void AT24CXX_WriteLenByte(u16 WriteAddr,u32 DataToWrite,u8 Len)
{   u8 t;for(t=0;t<Len;t++){AT24CXX_WriteOneByte(WriteAddr+t,(DataToWrite>>(8*t))&0xff);}
}//在AT24CXX里面的指定地址开始读出长度为Len的数据
//该函数用于读出16bit或者32bit的数据.
//ReadAddr   :开始读出的地址
//返回值     :数据
//Len        :要读出数据的长度2,4
u32 AT24CXX_ReadLenByte(u16 ReadAddr,u8 Len)
{   u8 t;u32 temp=0;for(t=0;t<Len;t++){temp<<=8;temp+=AT24CXX_ReadOneByte(ReadAddr+Len-t-1);                      }return temp;
}//检查AT24CXX是否正常
//这里用了24XX的最后一个地址(255)来存储标志字.
//如果用其他24C系列,这个地址要修改
//返回1:检测失败
//返回0:检测成功
u8 AT24CXX_Check(void)
{u8 temp;
temp = AT24CXX_ReadOneByte(255);//避免每次开机都写AT24CXX             if(temp==0X55)return 0;           else//排除第一次初始化的情况{AT24CXX_WriteOneByte(255,0X55);temp=AT24CXX_ReadOneByte(255);   if(temp==0X55)return 0;}return 1;
}//在AT24CXX里面的指定地址开始读出指定个数的数据
//ReadAddr :开始读出的地址 对24c02为0~255
//pBuffer  :数据数组首地址
//NumToRead:要读出数据的个数
void AT24CXX_Read(u16 ReadAddr,u8 *pBuffer,u16 NumToRead)
{while(NumToRead){*pBuffer++=AT24CXX_ReadOneByte(ReadAddr++);  NumToRead--;}
} //在AT24CXX里面的指定地址开始写入指定个数的数据
//WriteAddr :开始写入的地址 对24c02为0~255
//pBuffer   :数据数组首地址
//NumToWrite:要写入数据的个数
void AT24CXX_Write(u16 WriteAddr,u8 *pBuffer,u16 NumToWrite)
{while(NumToWrite--){AT24CXX_WriteOneByte(WriteAddr,*pBuffer);WriteAddr++;pBuffer++;}
}
  • 部分测试代码
const u8 TEXT_Buffer[]={"IIC AT24c02 测试"};
#define SIZE sizeof(TEXT_Buffer)
//需要自行配置串口
#define u1_printf(...) HAL_UART_Transmit((UART_HandleTypeDef *)&huart1,\(const uint8_t *)u1_data,\(uint16_t)sprintf((char *)u1_data,__VA_ARGS__),\(uint32_t)0xffff)uint8_t u1_data[2048];//设为全局
u8 datatemp[SIZE] = {0};AT24CXX_Init();                    //初始化IIC
while(AT24CXX_Check());//检测不到24c02
u1_printf("AT24C02 OK\r\n");AT24CXX_Write(0,(u8*)TEXT_Buffer,SIZE);
u1_printf("write ok\r\n");
AT24CXX_Read(0,datatemp,SIZE);
u1_printf("%s\r\n",datatemp)

4、利用iic拓展io

4.1、原理图


INT为拓展件的中断线 低电平有效
就是mcu用scl 和 sda 两根线 来 读写 p0 ~ p7 的引脚电平值

  • mcu往拓展件写数据

  • mcu从拓展件读数据

注意:一旦中断有效后,必须对 PCF8574T 进行一次读取/写入操作,复位中断,
才可以输出下一次中断,否则中断将一直保持(无法输出下一次输入信号变化所产生的中断)。

4.2、代码

代码就直接照搬正点原子的源码了

  • 头文件
#ifndef __PCF8574_H
#define __PCF8574_H
#include "sys.h"
#include "myiic.h"#define PCF8574_INT  PBin(12) //PCF8574 INT脚#define PCF8574_ADDR    0X40    //PCF8574地址(左移了一位)//PCF8574各个IO的功能
#define BEEP_IO         0       //蜂鸣器控制引脚   P0
#define AP_INT_IO       1       //AP3216C中断引脚   P1
#define DCMI_PWDN_IO    2       //DCMI的电源控制引脚   P2
#define USB_PWR_IO      3       //USB电源控制引脚 P3
#define EX_IO           4       //扩展IO,自定义使用    P4
#define MPU_INT_IO      5       //MPU9250中断引脚   P5
#define RS485_RE_IO     6       //RS485_RE引脚        P6
#define ETH_RESET_IO    7       //以太网复位引脚       P7u8 PCF8574_Init(void); //初始化
u8 PCF8574_ReadOneByte(void);
void PCF8574_WriteOneByte(u8 DataToWrite);
void PCF8574_WriteBit(u8 bit,u8 sta);//写入数据到指定引脚
u8 PCF8574_ReadBit(u8 bit);
#endif
  • 具体实现
#include "pcf8574.h"
#include "delay.h"//初始化PCF8574
u8 PCF8574_Init(void)
{u8 temp=0;GPIO_InitTypeDef GPIO_Initure;__HAL_RCC_GPIOB_CLK_ENABLE();           //使能GPIOB时钟GPIO_Initure.Pin=GPIO_PIN_12;           //PB12GPIO_Initure.Mode=GPIO_MODE_INPUT;      //输入GPIO_Initure.Pull=GPIO_PULLUP;          //上拉GPIO_Initure.Speed=GPIO_SPEED_HIGH;     //高速HAL_GPIO_Init(GPIOB,&GPIO_Initure);     //初始化IIC_Init();                             //IIC初始化
//检查PCF8574是否在位IIC_Start();            IIC_Send_Byte(PCF8574_ADDR);            //写地址               temp=IIC_Wait_Ack();                    //等待应答,通过判断是否有ACK应答,来判断PCF8574的状态IIC_Stop();                                //产生一个停止条件PCF8574_WriteOneByte(0XFF);               //默认情况下所有IO输出高电平return temp;
}//读取PCF8574的8位IO值
//返回值:读到的数据
u8 PCF8574_ReadOneByte(void)
{                 u8 temp=0;                                                                                IIC_Start();              IIC_Send_Byte(PCF8574_ADDR|0X01);   //进入接收模式            IIC_Wait_Ack();   temp=IIC_Read_Byte(0);           IIC_Stop();                          //产生一个停止条件      return temp;
}//向PCF8574写入8位IO值
//DataToWrite:要写入的数据
void PCF8574_WriteOneByte(u8 DataToWrite)
{                                                                                            IIC_Start();  IIC_Send_Byte(PCF8574_ADDR|0X00);   //发送器件地址0X40,写数据      IIC_Wait_Ack();                                                           IIC_Send_Byte(DataToWrite);          //发送字节                             IIC_Wait_Ack();      IIC_Stop();                         //产生一个停止条件 delay_ms(10);
}//设置PCF8574某个IO的高低电平
//bit:要设置的IO编号,0~7
//sta:IO的状态;0或1
void PCF8574_WriteBit(u8 bit,u8 sta)
{u8 data;data=PCF8574_ReadOneByte(); //先读出原来的设置if(sta==0){data&=~(1<<bit); //把bit位的置零    }else {data|=1<<bit;}PCF8574_WriteOneByte(data); //写入新的数据
}//读取PCF8574的某个IO的值
//bit:要读取的IO编号,0~7
//返回值:此IO的值,0或1
u8 PCF8574_ReadBit(u8 bit)
{u8 data;data=PCF8574_ReadOneByte(); //先读取这个8位IO的值 if(data&(1<<bit)){return 1;}else return 0;
}

CubeMx笔记 -- IIC(位带操作实现)+ IO拓展相关推荐

  1. 秉火429笔记之七位带操作

    目录 位带概况 位带概况 位操作,简单的理解,可以单独的对一个比特位读和写,51单片机非常常见.类如,51单片机通过关键字sbit来实现位定义,STM32并没有这个关键字,而是通过访问位带别名区(Bi ...

  2. Cortex‐M3和Cortex‐M0是否都能位带操作

    最近在进行stm32l011f4的编程,想到stm32有位带操作,便想试一试,但是事与愿违,先贴下位带操作代码 Cortex‐M0的位带操作代码 //IO输出方向设置 #define SDA_IN() ...

  3. STM32笔记 GPIO介绍及IO口操作 STM32F0 利用C语言位域实现仿位带操作

    文章目录 GPIO简介 工作方式 相关寄存器介绍 IO 操作步骤 IO口三种操作细解 附录:C语言相关 偏移地址与绝对地址 GPIO简介 GPIO:每个连接到I/O总线上的设备都有自己的I/O地址集, ...

  4. STM32 进阶教程 8 - 位带操作

    前言 有过51单片机开发经历的朋友应该都对51的IO口或一些特殊寄存器可以直接按位操作的方式不陌生吧,那么在stm32中有没有类似的操作呢,答案是肯定的,本节将给大家介绍如何在STM32中实现位带操作 ...

  5. 【STM32】标准库与HAL库对照学习教程六--位带操作

    [STM32]标准库与HAL库对照学习教程六--位带操作 一.前言 二.准备工作 三.位带介绍 1.位带操作 2.STM32位带及位带别名区域 四.位带区与位带别名区地址转换 五.GPIO的位带操作 ...

  6. STM32(五)------GPIO位带操作

    GPIO位带操作 介绍 位带简介 外设位带区 SRAM位带区 位带区和位带别名区地址转换 GPIO 位带操作 代码解析 GPIO 寄存器映射 GPIO位操作 主函数 介绍 位带简介 位操作就是可以单独 ...

  7. 3. GD32F103C8T6 GPIO的位带操作

    属于Contex M3 M4的内核有1M个区域的RAM和一个1M区域的外设地址可以实现位带操作 1.Contex M3 权威手册的说明 支持位带操作的两个内存区的范围是: 0x2000_0000‐0x ...

  8. 位带操作全解释,个人觉得不错就转过来理解下

    还记得51独有位操作,以一位(BIT)为数据对象的操作?可以简单的将P1口的第2位独立操作.P1.2=0;P1.2=1 ; 既可以把P1口的第三个脚(BIT2)置0置1. 而现在STM32的位段.位带 ...

  9. STM32的位带操作

    1. 什么是位带操作? 学习 51 单片机的时候就使用过位操作,通过关键字 sbit 对单片机IO口进行位定义.但STM32没有这样的关键字,于是便要通过访问位带别名区的方式来实现.即:将每一位膨胀成 ...

最新文章

  1. JS如何深度复制对象和数组,避免指针变量引用修改值
  2. C++ 一个例子彻底搞清楚拷贝构造函数和赋值运算符重载的区别
  3. WPF:仿WIN7窗体打开关闭效果
  4. Java 创建、填充PDF表单域
  5. WEB通用网关接口:CGI简单教程
  6. DOM-2 document对象、获取元素、节点、遍历树
  7. iOS- 关于AVAudioSession的使用——后台播放音乐
  8. 类与方法java讲解_Java中方法使用的深入讲解
  9. 奇异值与主成分分析(PCA)
  10. CISCO路由器的备份与还原(1)
  11. 电脑屏幕蓝光过滤护眼工具:f.lux for Mac
  12. 直通车点击率、点击率、创意图、关键词、出价卡位,提升直通车点击率的技巧和方法
  13. 二叉树——推荐一些神奇的网站
  14. 操作系统实践-BIOS
  15. twitter推文采集案例
  16. 嵌入式学习用什么编程语言
  17. import 模块大小写问题
  18. 素数筛(筛选法求素数)
  19. Linux中断——request_irq
  20. 日语语法准备一:日语词性的分类

热门文章

  1. 【githubshare】Linux sed 命令行常用汇总:useful-sed,收集了 sed 命令行的诸多常见用法,可用于快速处理文本文件
  2. FatMouse's Speed(LIS+路径记录)
  3. 人类为什么应当使用bilibili
  4. 从微博个性图标里学Android动态更换
  5. 《程序猿技术大咖》微信交流群
  6. 33_ue4进阶末日生存游戏开发[拾取面板UI]
  7. Unity(十七) 在Unity中Android使用FTP进行上传、下载、文件创建(客户端部分)
  8. 开源多端合一小程序源码系统+前端+后端+搭建教程
  9. 【经验】Chrome网络代理插件SwitchyOmega安装
  10. 甲骨文oracle测试面试记录