-- ------------------------------------------------------------------------------
-- Title: Calculate and set baudrate dynamically for USART 1
-- Arguments: baudrate
-- Returns: TRUE when succesful, otherwise FALSE
-- Notes: Uses bit-constant 'usart_hw_serial' to determine mode of operation:
-- * TRUE: Asynchronous communications (default)
-- * FALSE: Synchronous communications
-- ------------------------------------------------------------------------------
function _calculate_and_set_baudrate_dynamic(dword in baudrate)
return bit is
const max_deviation =
5 -- maximum % deviation of the desired baudrate
var dword usart_calculation, real_baud,
usart_div_low, usart_div_sync, clock
var word usart_div
var bit succes =
TRUE
clock =
dword(target_clock)
if (usart_hw_serial ==
TRUE)
then
-- USART in asynchronous mode
if (defined(BAUDCON_BRG16) ==
TRUE)
then -- use 16 bit baudrate register
BAUDCON_BRG16 = TRUE
TXSTA_BRGH = TRUE
usart_calculation = ((5 + ((10 *
clock) / (4 * baudrate))) /
10) -
1
usart_div = word(usart_calculation)
real_baud = clock /
4 / ((usart_div &
0xffff) +
1)
if (real_baud > baudrate)
then
if (100 * (real_baud -
baudrate) / baudrate >= max_deviation) then
-- Asynchronous baudrate deviation is too large
succes = FALSE
end if
else
if (100 * (baudrate - real_baud)
/ baudrate >= max_deviation) then
-- Asynchronous baudrate deviation is too large
succes = FALSE
end if
end if
SPBRGL = byte(usart_div) -- MSB
SPBRGH = byte(usart_div >>
8)
-- LSB
else
-- use classic (8 bit) baudrate register
-- <SPBRG> = ( Fosc / ( 4 * Baudrate ) ) -1
-- first try high baudrate, will generate highest accuarcy
-- to get the right rounding (5 + 10*f(x)) /10
usart_calculation =((5 + ((10 *
clock) / (16 * baudrate))) /
10) -
1
usart_div = word(usart_calculation)
-- special case if divider is 0, test if deviation is not too much
if usart_div ==
0 then
if (100 * (baudrate - (clock /
16))) / baudrate >= max_deviation
then
-- Asynchronous baudrate is too high
succes = FALSE
end if
end if
-- if divider small enough calculate divider and set high-speed
real_baud = clock /
16 / (usart_div +
1)
if usart_div <=
255 then
if (real_baud > baudrate)
then
if (100 * (real_baud
- baudrate) / baudrate >= max_deviation) then
-- Asynchronous baudrate deviation is too large
succes = FALSE
end if
else
if (100 * (baudrate
- real_baud) / baudrate >= max_deviation) then
-- Asynchronous baudrate deviation is too large
succes = FALSE
end if
end if
SPBRGL = byte(usart_div)
TXSTA_BRGH = TRUE
-- try the low-speed mode
else
usart_div_low = ((((10 *
clock) / (64 * baudrate)) +
5) /
10) -
1
-- here divider will never be 0
-- but special case to consider,
-- if baudrate is just a little too low
if (usart_div_low >
255) & (100 * ((clock /
(64 *
256 )) - baudrate)) /
baudrate < max_deviation
then
SPBRGL = 255
TXSTA_BRGH = FALSE
-- now calculate divider and set high-speed / low-speed bit
elsif usart_div_low <=
255 then
SPBRGL = byte(usart_div_low)
TXSTA_BRGH = FALSE
else
-- Asynchronous baudrate is too low
succes = FALSE
end if
end if
end if
else -- USART in synchronous mode
usart_div_sync = ( clock / (
4 * baudrate )) -
1
-- special case if divider is 0 or negative
-- test if baudrate is a little bit too high
if usart_div_sync <=
0 then
if (100 * (baudrate - (clock /
4))) / baudrate >= max_deviation
then
-- Synchronous baudrate is too high
succes = FALSE
end if
end if
-- special case to consider, if baudrate is just a little too high
if (usart_div_sync >
255) & (100 * ((clock /
(4 *
256)) - baudrate)) /
baudrate < max_deviation then
SPBRGL = 255
elsif (usart_div_sync <=
255)
then
SPBRGL = byte(usart_div_sync)
else
-- Synchronous baudrate is too low
succes = FALSE
end if
end if
return succes
end function