51单片机学习笔记
Posted 黑胡子大叔的小屋
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了51单片机学习笔记相关的知识,希望对你有一定的参考价值。
51单片机学习笔记
DS18B20温度传感器
常见温度传感器有数字温度传感器,还有模拟温度传感器。DS18B20为数字传感器,通信接口1-Wire(单总线),可寄生供电,可设置阈值,可设置精度。
单总线的接线有三条(GND、VCC、DQ),异步半双工,寄生供电时可以去除VCC线路。
电路规范:
- DQ需要配置成开漏输出模式
- DQ添加一个上拉电阻,组织一般为4.7KΩ
- 若从机采用寄生供电,主机还需要配一个强上拉输出电路
前两条同IIC
1-Wire时序结构
初始化
主机将总线拉低至少480us,然后释放总线,等待15 ~ 60us后,存在的从机会拉低总线60 ~ 240us响应主机,之后从机释放总线;分为两个部分:复位和响应。
/**
* @brief 主机将总线拉低至少480us,然后释放总线,等待15 ~ 60us后,
存在的从机会拉低总线60 ~ 240us响应主机,之后从机释放总线;
分为两个部分:复位和响应。
* @param
* @retval
*/
unsigned char OneWire_Init()
unsigned char i;
unsigned char AckBit;
OneWire_DQ = 1;
OneWire_DQ = 0; // 拉低总线
i = 247;
while (--i); // Delay 500us
OneWire_DQ = 1; // 释放总线
i = 32;
while (--i); // Delay 70us
AckBit = OneWire_DQ; // 获取从机响应
i = 247;
while (--i); // Delay 500us
return AckBit;
发送一位
主机将总线拉低60 ~ 120us,释放总线,表示发送0;主机将总线拉低1 ~14us,释放总线,表示发送1。从机将在主机拉低30us后读取电平,整个时间片应该大于60us。
/**
* @brief 主机将总线拉低60 ~ 120us,释放总线,表示发送0;
主机将总线拉低1 ~ 14us,释放总线,表示发送1。
从机将在主机拉低30us后读取电平,整个时间片应该大于60us。
在10us附近判断是否释放总线即可
* @param
* @retval
*/
void OneWire_SendBit(unsigned char Bit)
OneWire_DQ = 0; // 拉低总线
unsigned char i;
i = 4;
while (--i); // Delay 10us
OneWire_DQ = Bit;
i = 24;
while (--i); // Delay 50us
OneWire_DQ = 1;
接收一位
主机将总线拉低1 ~ 15us, 然后释放总线,并在拉低后15us内读取总线电平(尽量贴近15us末尾),读取低电平接收0,读取高电平接收1,整个时间片应该大于60us。
/**
* @brief 主机将总线拉低1 ~ 15us, 然后释放总线,并在拉低后15us内读取总线电平(尽量贴近15us末尾),
读取低电平接收0,读取高电平接收1,整个时间片应该大于60us。
* @param
* @retval
*/
unsigned char OneWrie_ReceiveBit()
unsigned char Bit;
unsigned char i;
OneWire_DQ = 0;
i = 2;
while (--i); // Delay 5us
OneWire_DQ = 1;
i = 2;
while (--i); // Delay 5us
Bit = OneWire_DQ;
i = 24;
while (--i); // Delay 50us
return Bit;
发送和接收一个字节
/**
* @brief 发送一个字节
* @param Byte 发送的字节
* @retval
*/
void OneWire_SendByte(unsigned char Byte)
unsigned char i;
for(i = 0; i < 8; i++)
OneWire_SendBit(Byte&(0x01<<i));
/**
* @brief 接收一个字节
* @param
* @retval 接收的数据
*/
unsigned char OneWire_ReceiveByte()
unsigned char i;
unsigned char Byte = 0x00;
for(i = 0; i < 8; i++)
if(OneWire_ReceiveBit())
Byte |= (0x01<<i);
return Byte;
DS18B20操作流程
- 初始化:从机复位,主机判断从机是否响应
- ROM操作:ROM指令 + 本指令需要的读写操作
ROM:
SEARCH ROM : 搜寻
READ ROM : 读
MATCH ROM : 匹配寻址
SKIP ROM :跳过,当接一个设备时使用
ALARM SEARCH :告警搜索
功能指令:
CONVERT T :温度变换
WRITE SCRATCHPAD:写
READ SCRATCHPAD:读暂存器内容
COPY SCRATCHPAD: 复制
RECALL E2:覆盖
READ POWER SUPPLY:响应供电方式,独立、寄生供电
- 功能操作:功能指令 + 本指令需要的读写操作
DS18B20数据帧
- 温度变化:初始化—>跳过ROM—>开始温度变换
- 温度读取:初始化—>跳过ROM—>读暂存器—>连续的读操作
直流电机驱动
电机驱动电路
- 大功率期间直接驱动
不能调换正负方向- H桥驱动
可以调控旋转方向
PWM电机调速
PWM 脉冲宽度调制,在具有惯性的系统中,可以通过对脉冲的宽度进行调制
代码实现
实现思路:通过定时器+中断+标志实现模拟出PWM
/**
* @brief 中断处理
* @desc 通过定时器控制频率,Counter和Compare的比较控制占空比
* @param 无
* @retval 无
*/
void Timer0_Routine() interrupt 1
static unsigned int T0Count;
TL0 = 0x9C;
TH0 = 0xFF;
Counter++;
Counter%=100;
if(Counter < Compare)
LED = 1;
else
LED = 0;
IIC总线
IIC概述
IIC时序结构
Start
起始条件:SCL高电平期间,SDA从高电平切换到低电平
/**
* @brief 起始
* @param
* @retval
*/
void I2C_Start(void)
I2C_SDA = 1;
I2C_SCL = 1;
I2C_SDA = 0;
I2C_SCL = 0;
Stop
终止条件:SCL高电平期间,SDA从低电平切换到高电平
/**
* @brief 终止
* @param
* @retval
*/
void I2C_Stop(void)
I2C_SDA = 0;
I2C_SCL = 1;
I2C_SDA = 1;
发送一个字节
SCL低电平期间,主机将数据位一次放到SDA先上(高位在前)
拉高SCL电平,从机在SCL高电平期间读取数据位
如此循环8次即可读一个字节
/**
* @brief 发送一个字节
* @param
* @retval
*/
void I2C_SendByte(unsigned char Byte)
unsigned char i;
for(i = 0; i < 8; i++)
I2C_SDA = Byte & (0x80 >> i);
I2C_SCL = 1;
I2C_SCL = 0;
接收一个字节
SCL低电平期间,从机将数据位依次放到SDA线上(高位在前)
拉高SCL,主机在SCL高电平时读取数据位
如此循环8次,即可接收一个字节(在接收前需要释放SDA,及SDA = 1)
/**
* @brief 接收一个字节
* @param
* @retval
*/
unsigned char ReceiveByte(void)
unsigned char i, Byte = 0x00;
I2C_SDA = 1;
for(i = 0; i < 8; i++)
I2C_SCL = 1;
if(I2C_SDA)
Byte |= (0x80 >> i);
I2C_SCL = 0;
return Byte;
发送应答
在接收完一个字节后,主机在下一个时钟发送一位数据,0标识应答,1标识非应答
/**
* @brief I2C发送应答
* @param AckBit 应答位,0为应答,1为非应答
* @retval 无
*/
void I2C_SendAck(unsigned char AckBit)
I2C_SDA = AckBit;
I2C_SCL = 1;
I2C_SCL = 0;
接收应答
在发送完一个字节滞后,主机在下一个时钟接收一位数据,判断从机是否应答,0标识应答,1标识非应答(主机在接收前,需要释放SDA)
/**
* @brief I2C接收应答位
* @param 无
* @retval 接收到的应答位,0为应答,1为非应答
*/
unsigned char I2C_ReceiveAck(void)
unsigned char AckBit;
I2C_SDA = 1;
I2C_SCL = 1;
AckBit = I2C_SDA;
I2C_SCL = 0;
return AckBit;
IIC数据帧
发送一帧数据
接收一帧数据
紫色部分为从机发送
AT24C02应用
/**
* @brief AT24C02写入一个字节
* @param WordAddress 要写入字节的地址
* @param Data 要写入的数据
* @retval 无
*/
void AT24C02_WriteByte(unsigned char WordAddress,Data)
I2C_Start();
I2C_SendByte(AT24C02_ADDRESS);
I2C_ReceiveAck();
I2C_SendByte(WordAddress);
I2C_ReceiveAck();
I2C_SendByte(Data);
I2C_ReceiveAck();
I2C_Stop();
/**
* @brief AT24C02读取一个字节
* @param WordAddress 要读出字节的地址
* @retval 读出的数据
*/
unsigned char AT24C02_ReadByte(unsigned char WordAddress)
unsigned char Data;
I2C_Start();
I2C_SendByte(AT24C02_ADDRESS);
I2C_ReceiveAck();
I2C_SendByte(WordAddress);
I2C_ReceiveAck();
I2C_Start();
I2C_SendByte(AT24C02_ADDRESS|0x01);
I2C_ReceiveAck();
Data = I2C_ReceiveByte();
I2C_SendAck(1);
I2C_Stop();
return Data;
以上是关于51单片机学习笔记的主要内容,如果未能解决你的问题,请参考以下文章
51单片机串口中断函数响应并返回后主函数运行到末尾后卡着不动,主函数无法循环了