文章目录
串口通信设备
串口 UART 协议
uart 串口波形
发送 0xFF 0X00 0X04 0X08数据
串行通信参数设置:BAUD:115200,8位数据,1个停止位,无奇偶校验,发送顺序为低位先发送。
波形实现方法:
- CPU 已实现,仅需设置寄存器
- GPIO管脚模拟波形
示例
//发送0x04 数据
void uart_tx(void)
{
GPA1CON = GPA1CON&~(0xf<<4)|(0x01<<4); //设置GPA1_1 GPIO输出模式
//开始位
GPA1DAT = GPA1DAT&~0x02 ; //设置GPA1_1 低电平
delay10ms();
//传数据 0x04 0000 0100
delay10ms(); //0
delay10ms(); //0
GPA1DAT = GPA1DAT|0x02 ; //1
delay10ms();
GPA1DAT = GPA1DAT&~0x02 ; //设置GPA1_1 低电平
delay10ms(); //0
delay10ms(); //0
delay10ms(); //0
delay10ms(); //0
//停止位
GPA1DAT = GPA1DAT|0x02 ; //1
delay10ms();
}
void uart_rx(void)
{
unsigned char output=0;
GPA1CON = GPA1CON&~(0xf); //设置GPA1_1 GPIO输入模式
//检测开始位
while(1)
{
if(GPA1DAT&0x01==0)
break;
delay10ms();
}
//接收数据
if(GPA1DAT&0x01==0) //bit0
output=0;
else
output=1;
if(GPA1DAT&0x01==0) //bit1
output=output&~(0x01<<1);
else
output=output|(0x01<<1);
if(GPA1DAT&0x01==0) //bit2
output=output&~(0x01<<2);
else
output=output|(0x01<<2);
....
}
I2C通信设备
I2C 协议
- I2C总PHLIPS公司在八十年代初推出的一种串行的半双工总线,主要用于连接整体电路。
- I2C总线为两线制,只有两根双向信号线。一根是数据线SDA,另一根是时钟线SCL。
- 总线速度分为标准速度100kbps,快速模式400kbps,高速模式3.4Mbps
- I2C硬件结构简单,接口连接方便,成本较低。因此在各个领域得到了广泛的应用。
- I2C是具备多主机系统所需的包括总线裁决功能的高性能串行总线。
- 每个接到I2C总线上的器件都有唯一的地址。主机与其它器件进行数据传送时总线上发送数据的器件为发送器,总线上接收数据的器件则为接收器。
IIC总线的数据传送
-
IIC的通信过程
主机发送起始信号启用总线
主机发送一字节数据指明从机地址与下一字节传送方向
对应的从机应答
发送器发送一字节数据
接收方应答
… …
数据传送完成后,主机发送停止信号释放总线使用权 -
起始信号与终止信号
SCL线为高电平期间,SDA线由高电平向低电平的变化表示起始信号
SCL线为高电平期间,SDA线由低电平向高电平的变化表示终止信
起始和终止信号都是由主机发出,起始信号产生后,总线就处于占用的态;终止信号产生后,总线就处于空闲态
-
字节传送与应答
每一个字节必须保证是8位长度。数据传送时,先传送最高位(MSB),每一个被传送的字节后面都必须跟随一位应答位(即一帧共有9位)
-
I2C总线进行数据传送时,时钟信号为高电平期间,数据线上的数据必须保持稳定,只有在时钟线上的信号为低电平期间,数据线上的高电平或低电平状态才允许变化。
IIC的寻址
- I2C总线上传送的数据信号是广义的,既包括地址信号,又包括真正的数据信号
- 主机在起始信号后必须传送一个从机的地址(7位),第8位是数据的传送方向位(R/T),用“0”表示主机发送数据(T),“1”表示主机接收数据(R)。总线上的每个从机都将这7位地址码与自己的地址进行比较,如果相同,则认为自己被主机寻址,根据R/T位将自己定为发送器或接收器
常见的传送方式
- 在总线的一传送过程中,可以有以下3种组合方式:
I2C 波形
往ID为0x3c的I2C 设备写数据 0x2e 0x2e …
1.由主机发起,在SCL为高电平时,SDA由高到低切 变,形成开始信号;
2.接着是7位地址和一位读写标志,这里7位地址为0111100,即0x3c,正是我们代码中设置的地址ID;最后一位为0表示写操作;
3.接着在下一个时钟,主机以高电平状态释放SDA,这时从机响应,将SDA拉低了;
4.接着是两个8位数据00101110与响应,即0x2E,
5.还有其它数据和最后的停止位,图中被截掉了
PWM
PWM的概念
- PWM(Pulse Width Modulation) :脉冲宽度调制
- 占空比:就是输出的PWM中,高电平保持的时间与该PWM的时钟周期的时间之比
PWM 蜂鸣器
PWM配置
step1:设置GPI/O为PWM模式
GPD0CON = (GPD0CON & ~(0xF << 0)) | (0x2 << 0);
step2:设置pwm频率
step2.1:第一级分频TCFG0
TCFG0 = (TCFG0 &~ (0xFF << 0)) | (100 << 0);
step2.2:第二级分频
TCFG1 = (TCFG1 &~ (0x0F << 0)) | (0x03<<0);
step2.3:第三级分频
TCNTB0 = 200;
step3:设置占空比
TCMPB0 = 100;
step4:启动定时器
TCON = (TCON & ~(0x0f << 0)) | (0x0A << 0);//先配置,先不启动
TCON = (TCON & ~(0x0f << 0)) | (0x09 << 0);//配置好了再启动
示例
/*
功能:实现K2 按下蜂鸣器发声,按下k3 蜂鸣器停止发声
*/
//----------------uart
#define GPA1CON (*(volatile unsigned int *)0x11400020) //volatile 确保本条指令不会因编译器的优化而省略
#define ULCON2 (*(volatile unsigned int *)0x13820000) //串口2线控:数据位,停止位,奇偶校验位
#define UCON2 (*(volatile unsigned int *)0x13820004) //串口2读取控制:串口读的方式(如:轮询/中断等),写的方式
#define UBRDIV2 (*(volatile unsigned int *)0x13820028) //串口2波特率设置
#define UFRACVAL2 (*(volatile unsigned int *)0x1382002c) //串口2波特率设置
#define UTXH2 (*(volatile unsigned int *)0x13820020) //串口2发送缓存器
#define URXH2 (*(volatile unsigned int *)0x13820024) //串口2接受缓存器
#define UTRSTAT2 (*(volatile unsigned int *)0x13820010) //串口2状态寄存器
#define GPA0CON (*(volatile unsigned int *)0x11400000) //volatile 确保本条指令不会因编译器的优化而省略
#define ULCON0 (*(volatile unsigned int *)0x13800000) //串口0线控:数据位,停止位,奇偶校验位
#define UCON0 (*(volatile unsigned int *)0x13800004) //串口0读取控制:串口读的方式(如:轮询/中断等),写的方式
#define UBRDIV0 (*(volatile unsigned int *)0x13800028) //串口0波特率设置
#define UFRACVAL0 (*(volatile unsigned int *)0x1380002c) //串口0波特率设置
#define UTXH0 (*(volatile unsigned int *)0x13800020) //串口0发送缓存器
#define URXH0 (*(volatile unsigned int *)0x13800024) //串口0接受缓存器
#define UTRSTAT0 (*(volatile unsigned int *)0x13800010) //串口0状态寄存器
#define ULCON3 (*(volatile unsigned int *)0x13830000) //串口3线控:数据位,停止位,奇偶校验位
#define UCON3 (*(volatile unsigned int *)0x13830004) //串口3读取控制:串口读的方式(如:轮询/中断等),写的方式
#define UBRDIV3 (*(volatile unsigned int *)0x13830028) //串口3波特率设置
#define UFRACVAL3 (*(volatile unsigned int *)0x1383002c) //串口3波特率设置
#define UTXH3 (*(volatile unsigned int *)0x13830020) //串口3发送缓存器
#define URXH3 (*(volatile unsigned int *)0x13830024) //串口3接受缓存器
#define UTRSTAT3 (*(volatile unsigned int *)0x13830010) //串口3状态寄存器
//---------------interrupt_init
#define GPX1CON (*(volatile unsigned int *)0x11000c20)
#define EXT_INT41CON (*(volatile int *)0x11000E04)
#define EXT_INT41_MASK (*(volatile int *)0x11000F04)
#define ICDISER1_CPU0 (*(volatile int *)0x10490104)
#define ICDIPTR14_CPU0 (*(volatile int *)0x10490838)
#define ICDDCR (*(volatile int *)0x10490000)
#define ICCICR_CPU0 (*(volatile int *)0x10480000)
#define ICCPMR_CPU0 (*(volatile int *)0x10480004)
#define EXT_INT41_PEND (*(volatile int *)0x11000f44)
#define ICCIAR_CPU0 (*(volatile int *)0x1048000C)
#define ICCEOIR_CPU0 (*(volatile int *)0x10480010)
#define ICDICPR1_CPU0 (*(volatile int *)0x10490284)
//-----------------led
#define GPX2CON (*(volatile unsigned int *)0x11000C40) //
#define GPF3CON (*(volatile unsigned int *)0x11000C20) //
#define GPX1DATA (*(volatile unsigned int *)0x11000C24) //
#define GPX2DATA (*(volatile unsigned int *)0x11000C44) //
#define GPF3DATA (*(volatile unsigned int *)0x114001E4) //
#define GPX2_7_H (GPX2DATA |= (0X01 << 7)) //LED2
#define GPX2_7_L (GPX2DATA &= ~(0X01 << 7))
#define GPX1_0_H (GPX1DATA |= (0X01 << 0)) //LED3
#define GPX1_0_L (GPX1DATA &= ~(0X01 << 0))
#define GPF3_4_H (GPF3DATA |= (0X01 << 4)) //LED4
#define GPF3_4_L (GPF3DATA &= ~(0X01 << 4)
#define GPF3_5_H (GPF3DATA |= (0X01 << 5)) //LED5
#define GPF3_5_L (GPF3DATA &= ~(0X01 << 5))
//------------------pwm
#define GPD0CON (*(volatile unsigned int *)0x114000a0) //
#define TCFG0 (*(volatile unsigned int *)0x139d0000) //pwm第一级分频,设置Prescaler
#define TCFG1 (*(volatile unsigned int *)0x139d0004) //pwm第二级分频
#define TCNTB0 (*(volatile unsigned int *)0x139d000c) //pwm第三级分频
#define TCMPB0 (*(volatile unsigned int *)0x139d0010) //设置占空比
#define TCON (*(volatile unsigned int *)0x139d0008) //定时器启动设置(定时器开启,波形翻转,更新定时器初值,自动重装载)
#define BEEP_ON 1
#define BEEP_OFF 2
typedef enum
{
DEVICE_UART_COM0 = 0,
DEVICE_UART_COM1 = 1,
DEVICE_UART_COM2 = 2,
DEVICE_UART_COM3 = 3,
DEVICE_BUTTON_KEY2,
DEVICE_BUTTON_KEY3,
DEVICE_PWM_BEEP,
MAX_DEVICE
} DEVICE_LIST_E;
/*
设置波特率为115200
//For example, if the Baud rate is 115200 bps and SCLK_UART is 100 MHz,UBRDIVn and UFRACVALn are:
//DIV_VAL = (SCLK_UART/(bps * 16)) - 1
//DIV_VAL = (100000000/(115200 * 16)) – 1
//= 54.253 – 1
//= 53.253
//UBRDIVn = 53 (integer part of DIV_VAL)
//UFRACVALn/16 = 0.253
//Therefore, UFRACVALn = 4
*/
void USART_Init(DEVICE_LIST_E Device_type)
{
if (Device_type == DEVICE_UART_COM0)
{
//1.配置GPA0CON寄存器中的UART0
//GPA0_0 UART_0_RXD
//GPA0_1 UART_0_TXD
GPA0CON &= 0xffffff00;
GPA0CON |= 0x00000022;
//2.配置ULCON0寄存器
//串口0 8位数据位,1位停止位,无奇偶校验
ULCON0 &= 0Xffffffc0;
ULCON0 |= 0x00000003;
//3.配置UCON0寄存器
//通过轮询(polling)的模式读取串口数据 通过轮询(polling)的模式往串口写入数据数据
UCON0 &= 0xfffffff0;
UCON0 |= 0x00000005;
//4.设置波特率为115200
UBRDIV0 = 53;
UFRACVAL0 = 4;
}
if (Device_type == DEVICE_UART_COM2)
{
GPA1CON &= 0xffffff00;
GPA1CON |= 0x00000022;
ULCON2 &= 0Xffffffc0;
ULCON2 |= 0x00000003;
UCON2 &= 0xfffffff0;
UCON2 |= 0x00000005;
UBRDIV2 = 53;
UFRACVAL2 = 4;
}
if (Device_type == DEVICE_UART_COM3)
{
GPA1CON &= 0xff00ffff;
GPA1CON |= 0x00220000;
ULCON3 &= 0Xffffffc0;
ULCON3 |= 0x00000003;
UCON3 &= 0xfffffff0;
UCON3 |= 0x00000005;
UBRDIV3 = 53;
UFRACVAL3 = 4;
}
}
void putc(DEVICE_LIST_E Device_type, char c)
{
switch (Device_type)
{
case DEVICE_UART_COM0:
while (1)
{
if (UTRSTAT0 && 0X02)
break;
}
UTXH0 = c;
break;
case DEVICE_UART_COM1:
break;
case DEVICE_UART_COM2:
while (1)
{
if (UTRSTAT2 && 0X02)
break;
}
UTXH2 = c;
break;
case DEVICE_UART_COM3:
while (1)
{
if (UTRSTAT3 && 0X02)
break;
}
break;
default:
break;
}
}
char getc(void)
{
while (1)
{
if (UTRSTAT0 && 0X01) break;
}
return URXH0;
}
void interrupt_init(DEVICE_LIST_E Device_type)
{
//KEY2的初始化设置
if (Device_type == DEVICE_BUTTON_KEY2)
{
//----- key2 GPX1_1 EINT9 SPIPORT:25 INTID:57
//-----外: 配置管脚的工作模式
//1-配置 GPX1_1为中断模式
GPX1CON = (GPX1CON & ~(0x0F << 4)) | (0x0F << 4);
//2-设置GPX1_1的触发方式为 下降沿触发
EXT_INT41CON = (EXT_INT41CON & ~(0x7 << 4)) | (0x2 << 4);
//3-GPX1_1 中断使能
EXT_INT41_MASK = (EXT_INT41_MASK & ~(0X01 << 1)) | (0X00 << 1);
//-----内: 功能块设置
//4-EINT9 (GPX1_1) GIC中断使能
ICDISER1_CPU0 = ICDISER1_CPU0 | (1 << 25);
//5-参考例子背景,用默认设置
ICDIPTR14_CPU0 = 0x01010101;
//6-GIC 分发总使能
ICDDCR = ICDDCR | 1;
//7-CPU0 中断使能
ICCICR_CPU0 = 1;
//8-设置CPU0的优先级门槛为最低
ICCPMR_CPU0 = 0XFF;
}
//KEY3的初始化设置
if (Device_type == DEVICE_BUTTON_KEY3)
{
//---- key3 GPX1_2 EINT10 SPIPORT:26 INTID:58
-----外: 配置管脚的工作模式
//1-配置 GPX1_2为中断模式
GPX1CON = (GPX1CON & ~(0x0F << 8)) | (0x0F << 8);
//2-设置GPX1_2的触发方式为 下降沿触发
EXT_INT41CON = (EXT_INT41CON & ~(0x7 << 8)) | (0x2 << 8);
//3-GPX1_2 中断使能
EXT_INT41_MASK = (EXT_INT41_MASK & ~(0X01 << 2)) | (0X00 << 2);
//-----内: 功能块设置
//4-EINT10 (GPX1_2) GIC中断使能
ICDISER1_CPU0 = ICDISER1_CPU0 | (1 << 26);
//5-参考例子背景,用默认设置
ICDIPTR14_CPU0 = 0x01010101;
//6-GIC 分发总使能
ICDDCR = ICDDCR | 1;
//7-CPU0 中断使能
ICCICR_CPU0 = 1;
//8-设置CPU0的优先级门槛为最低
ICCPMR_CPU0 = 0XFF;
}
}
void pwm_beep( int type)
{
if(type == BEEP_ON)
{
TCON = (TCON & ~(0x01 << 0)) | (0x01 << 0);//启动定时器(启动定时器beep)
}
if(type == BEEP_OFF)
{
TCON = (TCON & ~(0x01 << 0)) | (0x00 << 0);//关闭定时器(beep)
}
}
void do_irq(void )
{
int irq_num;
irq_num = ICCIAR_CPU0 & 0X3ff; //获取中断ID号
switch (irq_num)
{
//KEY2
case 57:
putc(DEVICE_UART_COM0, 'K');
putc(DEVICE_UART_COM0, '2');
pwm_beep(BEEP_ON);
EXT_INT41_PEND = EXT_INT41_PEND | (0X01 << 1); //清GPX1_1中断标志
ICDICPR1_CPU0 = ICDICPR1_CPU0 | (0x01 << 25); //清GCI中GPX1_1ç„中断标志
break;
//KEY3
case 58:
putc(DEVICE_UART_COM0, 'K');
putc(DEVICE_UART_COM0, '3');
pwm_beep(BEEP_OFF);
EXT_INT41_PEND = EXT_INT41_PEND | (0X01 << 2); //清GPX1_2中断标志
ICDICPR1_CPU0 = ICDICPR1_CPU0 | (0x01 << 26); //清GCI中GPX1_2中断标志
break;
default:
break;
}
ICCEOIR_CPU0 = (ICCEOIR_CPU0 & ~0x3ff) | irq_num; //结束对应的中断
}
void led_init(void)
{
GPX2CON = (GPX2CON & ~(0X0F << 28)) | (0X01 << 28); //设置LED2灯的配置寄存器 GPX2CON7为输出状态
GPX1CON = (GPX1CON & ~(0X0F << 0)) | (0X01 << 0); //设置LED3灯的配置寄存器 GPX1CON0为输出状态
GPF3CON = (GPF3CON & ~(0X0F << 16)) | (0X01 << 16); //设置LED4灯的配置寄存器 GPF3CON4为输出状态
GPF3CON = (GPF3CON & ~(0X0F << 20)) | (0X01 << 20); //设置LED5灯的配置寄存器 GPF3CON5为输出状态
}
void pwm_init(DEVICE_LIST_E Device_type)
{
if(Device_type == DEVICE_PWM_BEEP)
{
//----------外部 配置GPIO-----------------
//1.设置GPD0_0为PWM模式
GPD0CON = (GPD0CON & ~(0xF << 0)) | (0x2 << 0);
//-------------内部配置PWM功能块------------
//2.设置PWM周期为625Hz
// pwm_out = pclk/TCFG0/TCFG1/TCNTB0 = 100M/100/8/200 = 625HZ
TCFG0 = (TCFG0 &~ (0xFF << 0)) | (100 << 0);//设置第一级分频值为100
TCFG1 = (TCFG1 &~ (0x0F << 0)) | (0x03<<0); //设置第二级分频值为8
TCNTB0 = 200; //设置第三级分频值为200
//3.设置占空比为50%
TCMPB0 = 100; //设置占空比为 = TCMPB0/TCNTB0 = 100/200 = 1/2 ,输出的是方波
//4.启动定时器
TCON = (TCON & ~(0x0f << 0)) | (0x0A << 0);//先配置,先不启动
TCON = (TCON & ~(0x0f << 0)) | (0x09 << 0);//配置好了再启动
}
}
int main(void)
{
USART_Init(DEVICE_UART_COM0);
led_init();
interrupt_init(DEVICE_BUTTON_KEY2);
interrupt_init(DEVICE_BUTTON_KEY3);
pwm_init(DEVICE_PWM_BEEP);
char c;
while (1)
{
#if 0
c = getc();
delay1s();
putc(vDevice, c);
delay1s();
#endif
}
return 0;
}
参考
https://blog.youkuaiyun.com/m0_37542524/article/details/85947369