完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
扫一扫,分享给好友
CH438串口扩展芯片是一个一对八的串口扩展芯片,在一些串口需要过多的场合比较有用。这个串口芯片事实上并没有占用MCU的串口它实际上是使用了8个IO口做数据的传输。下面我就简单介绍一下怎么使用STM32驱动这个串口扩展芯片。并演示一个用CH438发送一段MODBUS码给电脑,电脑发给STM32的数据数据也回显示到电脑上.
CH438我用的是44管脚的LQFP44封装。 实际的电路是这样的: 需要注意的几点就是:RXT代表的是复位应该接上拉电阻到电源,我用的是STM32的复位电路共用。这里不能悬空。 晶振使用的是22.1184MHz晶振频率很高注意起振电容的选择。我采用的是20pf。 D0~D7与STM32 的PC0~7连接,这八位是数据传输位,其他的几位都是控制位。本次接收数据使用到了本芯片和STM32的中断,INT叫对应的就是中断线。注意这个管脚不能连接到PC口上因为PC口已经当做数据口用了,如果连接到PC口高八位上,在芯片读写数据的时候出异常。 下面这些是芯片内部的寄存器:主要就是配置他们。 #ifndef _CH438_H #define _CH438_H #include "sys.h" #include "delay.h" #define REG_RBR_ADDR 0x00 /* 串口0接收缓冲寄存器地址 */ #define REG_THR_ADDR 0x00 /* 串口0发送保持寄存器地址 */ #define REG_IER_ADDR 0x01 /* 串口0中断使能寄存器地址 */ #define REG_IIR_ADDR 0x02 /* 串口0中断识别寄存器地址 */ #define REG_FCR_ADDR 0x02 /* 串口0FIFO控制寄存器地址 */ #define REG_LCR_ADDR 0x03 /* 串口0线路控制寄存器地址 */ #define REG_MCR_ADDR 0x04 /* 串口0MODEM控制寄存器地址 */ #define REG_LSR_ADDR 0x05 /* 串口0线路状态寄存器地址 */ #define REG_MSR_ADDR 0x06 /* 串口0MODEM状态寄存器地址 */ #define REG_SCR_ADDR 0x07 /* 串口0用户可定义寄存器地址 */ #define REG_DLL_ADDR 0x00 /* 波特率除数锁存器低8位字节地址 */ #define REG_DLM_ADDR 0x01 /* 波特率除数锁存器高8位字节地址 */ /* CH438内部串口0~7 专用状态寄存器 */ #define REG_SSR_ADDR 0x4F /* 专用状态寄存器地址 */ /* IER寄存器的位 */ #define BIT_IER_RESET 0x80 /* 该位置1则软复位该串口 */ #define BIT_IER_LOWPOWER 0x40 /* 该位为1则关闭该串口的内部基准时钟 */ #define BIT_IER_SLP 0x20 /* 串口0是SLP,为1则关闭时钟震荡器 */ #define BIT_IER1_CK2X 0x20 /* 串口1是CK2X,为1则强制将外部时钟信号2倍频后作为内部基准时钟 */ #define BIT_IER_IEMODEM 0x08 /* 该位为1允许MODEM输入状态变化中断 */ #define BIT_IER_IELINES 0x04 /* 该位为1允许接收线路状态中断 */ #define BIT_IER_IETHRE 0x02 /* 该位为1允许发送保持寄存器空中断 */ #define BIT_IER_IERECV 0x01 /* 该位为1允许接收到数据中断 */ /* IIR寄存器的位 */ #define BIT_IIR_FIFOENS1 0x80 #define BIT_IIR_FIFOENS0 0x40 /* 该2位为1表示起用FIFO */ /* 中断类型:0001没有中断,0110接收线路状态中断,0100接收数据可用中断,1100接收数据超时中断,0010THR寄存器空中断,0000MODEM输入变化中断 */ #define BIT_IIR_IID3 0x08 #define BIT_IIR_IID2 0x04 //接受数据可用 #define BIT_IIR_IID1 0x02 //THR寄存器空中断 #define BIT_IIR_NOINT 0x01 /* FCR寄存器的位 */ /* 触发点: 00对应1个字节,01对应16个字节,10对应64个字节,11对应112个字节 */ #define BIT_FCR_RECVTG1 0x80 /* 设置FIFO的中断和自动硬件流控制的触发点 */ #define BIT_FCR_RECVTG0 0x40 /* 设置FIFO的中断和自动硬件流控制的触发点 */ #define BIT_FCR_TFIFORST 0x04 /* 该位置1则清空发送FIFO中的数据 */ #define BIT_FCR_RFIFORST 0x02 /* 该位置1则清空接收FIFO中的数据 */ #define BIT_FCR_FIFOEN 0x01 /* 该位置1则起用FIFO,为0则禁用FIFO */ /* LCR寄存器的位 */ #define BIT_LCR_DLAB 0x80 /* 为1才能存取DLL,DLM,为0才能存取RBR/THR/IER */ #define BIT_LCR_BREAKEN 0x40 /* 为1则强制产生BREAK线路间隔*/ /* 设置校验格式:当PAREN为1时,00奇校验,01偶校验,10标志位(MARK,置1),11空白位(SPACE,清0) */ #define BIT_LCR_PARMODE1 0x20 /* 设置奇偶校验位格式 */ #define BIT_LCR_PARMODE0 0x10 /* 设置奇偶校验位格式 */ #define BIT_LCR_PAREN 0x08 /* 为1则允许发送时产生和接收校验奇偶校验位 */ #define BIT_LCR_STOPBIT 0x04 /* 为1则两个停止位,为0一个停止位 */ /* 设置字长度:00则5个数据位,01则6个数据位,10则7个数据位,11则8个数据位 */ #define BIT_LCR_WORDSZ1 0x02 /* 设置字长长度 */ #define BIT_LCR_WORDSZ0 0x01 /* MCR寄存器的位 */ #define BIT_MCR_AFE 0x20 /* 为1允许CTS和RTS硬件自动流控制 */ #define BIT_MCR_LOOP 0x10 /* 为1使能内部回路的测试模式 */ #define BIT_MCR_OUT2 0x08 /* 为1允许该串口的中断请求输出 */ #define BIT_MCR_OUT1 0x04 /* 为用户定义的MODEM控制位 */ #define BIT_MCR_RTS 0x02 /* 该位为1则RTS引脚输出有效 */ #define BIT_MCR_DTR 0x01 /* 该位为1则DTR引脚输出有效 */ /* LSR寄存器的位 */ #define BIT_LSR_RFIFOERR 0x80 /* 为1表示在接收FIFO中存在至少一个错误 */ #define BIT_LSR_TEMT 0x40 /* 为1表示THR和TSR全空 */ #define BIT_LSR_THRE 0x20 /* 为1表示THR空*/ #define BIT_LSR_BREAKINT 0x10 /* 该位为1表示检测到BREAK线路间隔 */ #define BIT_LSR_FRAMEERR 0x08 /* 该位为1表示读取数据帧错误 */ #define BIT_LSR_PARERR 0x04 /* 该位为1表示奇偶校验错误 */ #define BIT_LSR_OVERR 0x02 /* 为1表示接收FIFO缓冲区溢出 */ #define BIT_LSR_DATARDY 0x01 /* 该位为1表示接收FIFO中有接收到的数据 */ /* MSR寄存器的位 */ #define BIT_MSR_DCD 0x80 /* 该位为1表示DCD引脚有效 */ #define BIT_MSR_RI 0x40 /* 该位为1表示RI引脚有效 */ #define BIT_MSR_DSR 0x20 /* 该位为1表示DSR引脚有效 */ #define BIT_MSR_CTS 0x10 /* 该位为1表示CTS引脚有效 */ #define BIT_MSR_DDCD 0x08 /* 该位为1表示DCD引脚输入状态发生变化过 */ #define BIT_MSR_TERI 0x04 /* 该位为1表示RI引脚输入状态发生变化过 */ #define BIT_MSR_DDSR 0x02 /* 该位为1表示DSR引脚输入状态发生变化过 */ #define BIT_MSR_DCTS 0x01 /* 该位为1表示CTS引脚输入状态发生变化过 */ /* 中断状态码 */ #define INT_NOINT 0x01 /* 没有中断 */ #define INT_THR_EMPTY 0x02 /* THR空中断 */ #define INT_RCV_OVERTIME 0x0C /* 接收超时中断 */ #define INT_RCV_SUCCESS 0x04 /* 接收数据可用中断 */ #define INT_RCV_LINES 0x06 /* 接收线路状态中断 */ #define INT_MODEM_CHANGE 0x00 /* MODEM输入变化中断 */ #define CH438_IIR_FIFOS_ENABLED 0xC0 /* 起用FIFO */ #define WR PDout(3) #define ALE PDout(7) #define RD PDout(4) #define CS PDout(5) #define AMOD PDout(6) #define INT PDout(1) void SetOutPut(void); void SetInPut(void); void CH438_Init(void); void CH438WriteReg(u8 add,u8 data); u8 CH438ReadReg(u8 add); unsigned char CH438_CheckIIR(unsigned char num); void CH438_CloseSeril(unsigned char num); void CH438_CloseALLSeril(void); void CH438_ResetSeril(unsigned char num); void CH438_SetBandrate(unsigned char num, unsigned long value); void CH438_UARTInit(unsigned char num); void CH438_SendDatas(unsigned char num, unsigned char* sendbuff,unsigned char len); unsigned char CH438_RecvDatas(unsigned char num, unsigned char* revbuff); void CH438_TranConfig(unsigned char num); void CH438_INTConfig(unsigned char num); void CH438_AutoHFCtrl(unsigned char num); void CH438_RegTEST(unsigned char num); void CH438_Uart_Init(unsigned char num,unsigned long value); #endif 上面就是CH438.h头文件,以下就是main函数,本程序只打开了串口2 int main() { u8 ssr =0 ; u8 AddCom[8] = {01,05,01,17,255,00,221,195}; //增压 delay_init(); NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 设置中断优先级分组2 uart_init(9600); LCD_Init(); CH438_Init(); CH438_ResetSeril(2); //软件复位串口2 CH438_Uart_Init(2,9600); //串口2打开 波特率9600 delay_ms(100); while(1) { CH438_SendDatas(2,AddCom,8); CH438_SendDatas(2,(u8*)"rn",2); delay_ms(1000); } } 下面是主要的函数 #include "ch438.h" #include "delay.h" #include "usart.h" #include "lcd.h" #define Fpclk 1843200 /* 定义内部时钟频率,默认外部晶振的12分频 */ #define MaxRecvLen 50 /* 接收缓冲区大小 */ const unsigned char offsetadd[] = {0x00,0x10,0x20,0x30,0x08,0x18,0x28,0x38,}; /* 串口号的偏移地址 */ const unsigned char Interruptnum[] = {0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,}; /* SSR寄存器中断号对应值 */ unsigned char Revbuff[MaxRecvLen]; /* 接收缓存区 */ unsigned char RevLen; /* 接收计数 */ void SetOutPut() //IO输出模式 { GPIOC->CRL &=0; GPIOC->CRL = 0X33333333; } void SetInPut()//IO输入模式 { GPIOC->CRL &=0; GPIOC->CRL = 0X88888888; } void CH438_Init() //IO口中断等初始化 { GPIO_InitTypeDef GPIO_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; EXTI_InitTypeDef EXTI_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC|RCC_APB2Periph_GPIOD,ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Pin = 0X00FF; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOC,&GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7; GPIO_Init(GPIOD,&GPIO_InitStructure); GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; GPIO_Init(GPIOD,&GPIO_InitStructure); GPIO_EXTILineConfig(GPIO_PortSourceGPIOD,GPIO_PinSource1); EXTI_InitStructure.EXTI_Line = EXTI_Line1; EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; EXTI_InitStructure.EXTI_LineCmd = ENABLE; EXTI_Init(&EXTI_InitStructure); NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; NVIC_InitStructure.NVIC_IRQChannelSubPriority=2; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); EXTI_ClearITPendingBit(EXTI_Line1); AMOD = 1; } void CH438WriteReg(u8 add,u8 data) //写一个字节到寄存器 { u16 value ; CS = 1; WR = 1; RD = 1; SetOutPut(); GPIOC->ODR = (GPIOC->ODR&0XFF00)|add; //低八位十数据位确保高八位数据不变 写寄存器地址 CS = 0; ALE =1; delay_us(1); ALE = 0; GPIOC->ODR = (GPIOC->ODR&0XFF00)|data; //写数据 WR =0 ; delay_us(1); WR =1; CS =1; } u8 CH438ReadReg(u8 add) //读取一个字节 { u8 value; u8 value1; CS = 1; WR =1; RD =1; SetOutPut(); // CS = 0; ALE =1; GPIOC->ODR = (GPIOC->ODR&0XFF00)|add; ALE = 0; SetInPut(); RD = 0; value = GPIO_ReadInputData(GPIOC); RD =1; CS =1; return value; } unsigned char CH438_CheckIIR(unsigned char num) { unsigned char value; value = CH438ReadReg( offsetadd[num] | REG_IIR_ADDR ); return value; } void CH438_CloseSeril(unsigned char num) //关闭某位串口 { CH438WriteReg(offsetadd[num]|REG_IER_ADDR, BIT_IER_LOWPOWER); } void CH438_CloseALLSeril(void) //关闭所有串口 { CH438WriteReg(offsetadd[0]|REG_IER_ADDR, BIT_IER_LOWPOWER|BIT_IER_SLP); } void CH438_ResetSeril(unsigned char num) //复位串口 { CH438WriteReg(offsetadd[num]|REG_IER_ADDR, BIT_IER_RESET); } void CH438_SetBandrate(unsigned char num, unsigned long value)//设置波特率 未使用此函数 { uint8_t dlab=0; uint16_t bandspeed; bandspeed = Fpclk/16/value; CH438WriteReg(offsetadd[num]|REG_LCR_ADDR, BIT_LCR_DLAB ); CH438WriteReg(offsetadd[num]|REG_DLL_ADDR, (uint8_t)bandspeed); CH438WriteReg(offsetadd[num]|REG_DLM_ADDR, (uint8_t)(bandspeed>>8)); printf("bandrate: %dn", bandspeed); printf("DLM: %dn", CH438ReadReg(offsetadd[num]|REG_DLM_ADDR)); printf("DLL: %dn", CH438ReadReg(offsetadd[num]|REG_DLL_ADDR)); } void CH438_UARTInit(unsigned char num)//初始化 未使用到 { CH438_SetBandrate(num, 9600); /* CH438串口1波特率设置 */ CH438_TranConfig(num); /* CH438串口1数据格式配置及FIFO大小 */ } //发送数据 void CH438_SendDatas(unsigned char num, unsigned char* sendbuff,unsigned char len) { do { while((CH438ReadReg(offsetadd[num]|REG_LSR_ADDR)&BIT_LSR_THRE)==0); //LSR->THRE==1 保持寄存器空 CH438WriteReg(offsetadd[num]|REG_THR_ADDR,*sendbuff++); }while(--len); } //接收数据 unsigned char CH438_RecvDatas(unsigned char num, unsigned char* revbuff) { uint8_t len=0; uint8_t *p_rev; p_rev = revbuff; while( ( CH438ReadReg( offsetadd[num]|REG_LSR_ADDR ) & BIT_LSR_DATARDY ) == 0 ); /*等待数据准备好 */ while((CH438ReadReg(offsetadd[num]|REG_LSR_ADDR)&BIT_LSR_DATARDY)) //LSR->DATARDY==1 { *p_rev = CH438ReadReg(offsetadd[num]|REG_RBR_ADDR); p_rev++; len++; } return len; } void CH438_TranConfig(unsigned char num) { /* 发送数据格式:8位数据,无校验,1个停止位 */ CH438WriteReg(offsetadd[num]|REG_LCR_ADDR, BIT_LCR_WORDSZ1 | BIT_LCR_WORDSZ0); /* 设置FIFO模式,触发点为112字节 */ CH438WriteReg(offsetadd[num]|REG_FCR_ADDR, BIT_FCR_RECVTG1 | BIT_FCR_RECVTG0 | BIT_FCR_FIFOEN); CH438WriteReg(offsetadd[num]|REG_FCR_ADDR,CH438ReadReg(offsetadd[num]|REG_FCR_ADDR)| BIT_FCR_TFIFORST|BIT_FCR_RFIFORST); } void CH438_INTConfig(unsigned char num) { /* 注意: CH438打开BIT_IER_IETHRE中断(0->1),会产生一个发生空中断 */ CH438WriteReg(offsetadd[num]|REG_IER_ADDR, BIT_IER_IELINES | BIT_IER_IETHRE | BIT_IER_IERECV ); CH438_CheckIIR(num); CH438WriteReg(offsetadd[num]|REG_MCR_ADDR, BIT_MCR_OUT2 | BIT_MCR_RTS | BIT_MCR_DTR);//可以产生一个实际的中断 } void CH438_AutoHFCtrl(unsigned char num) { CH438WriteReg( offsetadd[num]|REG_MCR_ADDR, BIT_MCR_AFE | BIT_MCR_OUT2 | BIT_MCR_RTS );/* 设置MCR寄存器的AFE和RTS为1 */ } //中断处理函数 void EXTI1_IRQHandler() { u8 gInterruptStatus; u8 InterruptStatus; u8 i; static u8 j ; if(EXTI_GetITStatus(EXTI_Line1)!= RESET) { gInterruptStatus = CH438ReadReg( REG_SSR_ADDR ); if(!gInterruptStatus) { EXTI_ClearITPendingBit(EXTI_Line1); return ; } for(i=0; i<8; i++) { if( gInterruptStatus & Interruptnum ) /* 检测哪个串口发生中断 */ { InterruptStatus = CH438ReadReg( offsetadd | REG_IIR_ADDR ) & 0x0f; /* 读串口的中断状态 */ switch( InterruptStatus ) { case INT_NOINT: /* 没有中断 */ break; case INT_THR_EMPTY: /* THR空中断 */ break; case INT_RCV_OVERTIME: /* 接收超时中断 */ RevLen = CH438_RecvDatas(i, Revbuff); CH438_SendDatas(i, Revbuff, RevLen); break; case INT_RCV_SUCCESS: /* 接收数据可用中断 */ RevLen = CH438_RecvDatas(i, Revbuff); CH438_SendDatas(i, Revbuff, RevLen); break; case INT_RCV_LINES: /* 接收线路状态中断 */ CH438ReadReg( offsetadd | REG_LSR_ADDR ); break; case INT_MODEM_CHANGE: /* MODEM输入变化中断 */ CH438ReadReg( offsetadd | REG_MSR_ADDR ); break; default: break; } } } EXTI_ClearITPendingBit(EXTI_Line1); } } void CH438_RegTEST(unsigned char num)//测试使用的函数 { printf("current test serilnum: %d rn",(unsigned short)offsetadd[num]); printf("IER: %02xrn",(unsigned short)CH438ReadReg(offsetadd[num] | REG_IER_ADDR));//?IER printf("IIR: %02xrn",(unsigned short)CH438ReadReg(offsetadd[num] | REG_IIR_ADDR));//?IIR printf("LCR: %02xrn",(unsigned short)CH438ReadReg(offsetadd[num] | REG_LCR_ADDR));//?LCR printf("MCR: %02xrn",(unsigned short)CH438ReadReg(offsetadd[num] | REG_MCR_ADDR));//?MCR printf("LSR: %02xrn",(unsigned short)CH438ReadReg(offsetadd[num] | REG_LSR_ADDR));//?LSR printf("MSR: %02xrn",(unsigned short)CH438ReadReg(offsetadd[num] | REG_MSR_ADDR));//?MSR //CH438WriteReg(offsetadd[num] | REG_SCR_ADDR, 0x78); printf("SCR: %02xrn",(unsigned short)CH438ReadReg(offsetadd[num] | REG_SCR_ADDR));//?SCR printf("FCR: %02xrn",(unsigned short)CH438ReadReg(offsetadd[num] | REG_FCR_ADDR));//?SCR } //串口初始化函数 输入参数 串口号和波特率 void CH438_Uart_Init(unsigned char num,unsigned long value) { uint8_t dlab=0; uint16_t bandspeed; dlab = CH438ReadReg(offsetadd[num]|REG_IER_ADDR); dlab &= 0xDF; CH438WriteReg(offsetadd[num]|REG_IER_ADDR, dlab); dlab = CH438ReadReg(offsetadd[num]|REG_LCR_ADDR); dlab |= 0x80; //置LCR寄存器DLAB位为1 CH438WriteReg(offsetadd[num]|REG_LCR_ADDR, dlab); bandspeed = Fpclk/16/value; CH438WriteReg(offsetadd[num]|REG_DLL_ADDR, (uint8_t)bandspeed); CH438WriteReg(offsetadd[num]|REG_DLM_ADDR, (uint8_t)(bandspeed>>8)); dlab &= 0x7F; //置IIR寄存器DLAB位为0 CH438WriteReg(offsetadd[num]|REG_LCR_ADDR, dlab); CH438WriteReg(offsetadd[num]|REG_FCR_ADDR,BIT_FCR_RECVTG1 | BIT_FCR_RECVTG0 | BIT_FCR_FIFOEN ); CH438WriteReg(offsetadd[num]|REG_LCR_ADDR,BIT_LCR_WORDSZ1 | BIT_LCR_WORDSZ0 ); CH438WriteReg(offsetadd[num]|REG_IER_ADDR,BIT_IER_IELINES | BIT_IER_IETHRE | BIT_IER_IERECV); CH438WriteReg(offsetadd[num]|REG_MCR_ADDR,BIT_MCR_OUT2 | BIT_MCR_RTS | BIT_MCR_DTR); CH438WriteReg(offsetadd[num]|REG_FCR_ADDR,CH438ReadReg(offsetadd[num]|REG_FCR_ADDR)| BIT_FCR_TFIFORST|BIT_FCR_RFIFORST); } 实验结果如下: |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1792 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1626 浏览 1 评论
1094 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
732 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1682 浏览 2 评论
1943浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
740浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
577浏览 3评论
600浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
562浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-26 04:55 , Processed in 0.797054 second(s), Total 77, Slave 61 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号